@effect/language-service 0.3.1 → 0.4.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.
@@ -723,19 +723,16 @@ function createDiagnostic(definition) {
723
723
  // src/utils/TypeParser.ts
724
724
  var covariantTypeArgument = (type) => {
725
725
  const signatures = type.getCallSignatures();
726
- if (signatures.length !== 1)
727
- return none2();
726
+ if (signatures.length !== 1) return none2();
728
727
  return some2(signatures[0].getReturnType());
729
728
  };
730
729
  function pipeableType(ts, typeChecker) {
731
730
  return (type, atLocation) => {
732
731
  const pipeSymbol = typeChecker.getPropertyOfType(type, "pipe");
733
- if (!pipeSymbol)
734
- return none2();
732
+ if (!pipeSymbol) return none2();
735
733
  const pipeType = typeChecker.getTypeOfSymbolAtLocation(pipeSymbol, atLocation);
736
734
  const signatures = pipeType.getCallSignatures();
737
- if (signatures.length === 0)
738
- return none2();
735
+ if (signatures.length === 0) return none2();
739
736
  return some2(type);
740
737
  };
741
738
  }
@@ -779,8 +776,16 @@ function fiberType(ts, typeChecker) {
779
776
  const pollSymbol = yield* fromNullable(
780
777
  typeChecker.getPropertyOfType(type, "poll")
781
778
  );
782
- if (!awaitSymbol || !pollSymbol)
783
- return yield* none2();
779
+ if (!awaitSymbol || !pollSymbol) return yield* none2();
780
+ return effectType(ts, typeChecker)(type, atLocation);
781
+ });
782
+ }
783
+ function effectSubtype(ts, typeChecker) {
784
+ return (type, atLocation) => gen(function* (_) {
785
+ const tagSymbol = yield* fromNullable(
786
+ typeChecker.getPropertyOfType(type, "_tag")
787
+ );
788
+ if (!tagSymbol) return yield* none2();
784
789
  return effectType(ts, typeChecker)(type, atLocation);
785
790
  });
786
791
  }
@@ -798,20 +803,51 @@ function importedEffectModule(ts, typeChecker) {
798
803
  }
799
804
  function effectGen(ts, typeChecker) {
800
805
  return (node) => gen(function* () {
801
- if (!ts.isCallExpression(node))
802
- return yield* none2();
803
- if (node.arguments.length === 0)
804
- return yield* none2();
806
+ if (!ts.isCallExpression(node)) return yield* none2();
807
+ if (node.arguments.length === 0) return yield* none2();
805
808
  const generatorFunction = node.arguments[0];
806
- if (!ts.isFunctionExpression(generatorFunction))
807
- return yield* none2();
808
- if (generatorFunction.asteriskToken === void 0)
809
- return yield* none2();
810
- if (!ts.isPropertyAccessExpression(node.expression))
811
- return yield* none2();
809
+ if (!ts.isFunctionExpression(generatorFunction)) return yield* none2();
810
+ if (generatorFunction.asteriskToken === void 0) return yield* none2();
811
+ if (!ts.isPropertyAccessExpression(node.expression)) return yield* none2();
812
812
  const propertyAccess = node.expression;
813
- if (propertyAccess.name.text !== "gen")
814
- return yield* none2();
813
+ if (propertyAccess.name.text !== "gen") return yield* none2();
814
+ return yield* importedEffectModule(ts, typeChecker)(propertyAccess.expression).pipe(
815
+ map(() => ({
816
+ body: generatorFunction.body,
817
+ functionStar: generatorFunction.getFirstToken()
818
+ }))
819
+ );
820
+ });
821
+ }
822
+ function effectFnUntracedGen(ts, typeChecker) {
823
+ return (node) => gen(function* () {
824
+ if (!ts.isCallExpression(node)) return yield* none2();
825
+ if (node.arguments.length === 0) return yield* none2();
826
+ const generatorFunction = node.arguments[0];
827
+ if (!ts.isFunctionExpression(generatorFunction)) return yield* none2();
828
+ if (generatorFunction.asteriskToken === void 0) return yield* none2();
829
+ if (!ts.isPropertyAccessExpression(node.expression)) return yield* none2();
830
+ const propertyAccess = node.expression;
831
+ if (propertyAccess.name.text !== "fnUntraced") return yield* none2();
832
+ return yield* importedEffectModule(ts, typeChecker)(propertyAccess.expression).pipe(
833
+ map(() => ({
834
+ body: generatorFunction.body,
835
+ functionStar: generatorFunction.getFirstToken()
836
+ }))
837
+ );
838
+ });
839
+ }
840
+ function effectFnGen(ts, typeChecker) {
841
+ return (node) => gen(function* () {
842
+ if (!ts.isCallExpression(node)) return yield* none2();
843
+ if (node.arguments.length === 0) return yield* none2();
844
+ const generatorFunction = node.arguments[0];
845
+ if (!ts.isFunctionExpression(generatorFunction)) return yield* none2();
846
+ if (generatorFunction.asteriskToken === void 0) return yield* none2();
847
+ const expressionToTest = ts.isCallExpression(node.expression) ? node.expression.expression : node.expression;
848
+ if (!ts.isPropertyAccessExpression(expressionToTest)) return yield* none2();
849
+ const propertyAccess = expressionToTest;
850
+ if (propertyAccess.name.text !== "fn") return yield* none2();
815
851
  return yield* importedEffectModule(ts, typeChecker)(propertyAccess.expression).pipe(
816
852
  map(() => ({
817
853
  body: generatorFunction.body,
@@ -861,15 +897,13 @@ function expectedAndRealType(ts, typeChecker) {
861
897
  if (ts.isReturnStatement(node) && node.expression) {
862
898
  const expectedType = typeChecker.getContextualType(node.expression);
863
899
  const realType = typeChecker.getTypeAtLocation(node.expression);
864
- if (expectedType)
865
- return [[node, expectedType, node, realType]];
900
+ if (expectedType) return [[node, expectedType, node, realType]];
866
901
  }
867
902
  if (ts.isArrowFunction(node) && ts.isExpression(node.body)) {
868
903
  const body = node.body;
869
904
  const expectedType = typeChecker.getContextualType(body);
870
905
  const realType = typeChecker.getTypeAtLocation(body);
871
- if (expectedType)
872
- return [[body, expectedType, body, realType]];
906
+ if (expectedType) return [[body, expectedType, body, realType]];
873
907
  }
874
908
  if (ts.isSatisfiesExpression(node)) {
875
909
  const expectedType = typeChecker.getTypeAtLocation(node.type);
@@ -886,13 +920,23 @@ var floatingEffect = createDiagnostic({
886
920
  apply: (ts, program) => (sourceFile) => {
887
921
  const typeChecker = program.getTypeChecker();
888
922
  const effectDiagnostics = [];
923
+ function isFloatingExpression(node) {
924
+ if (!ts.isExpressionStatement(node)) return false;
925
+ if (!(ts.isBlock(node.parent) || ts.isSourceFile(node.parent))) return false;
926
+ const expression = node.expression;
927
+ if (ts.isBinaryExpression(expression) && expression.operatorToken && expression.operatorToken.kind === ts.SyntaxKind.EqualsToken) return false;
928
+ return true;
929
+ }
889
930
  const visit = (node) => {
890
- if (ts.isExpressionStatement(node) && (ts.isBlock(node.parent) || ts.isSourceFile(node.parent))) {
931
+ if (isFloatingExpression(node)) {
891
932
  const type = typeChecker.getTypeAtLocation(node.expression);
892
933
  const effect = effectType(ts, typeChecker)(type, node.expression);
893
934
  if (isSome2(effect)) {
894
- const fiber = fiberType(ts, typeChecker)(type, node.expression);
895
- if (isNone2(fiber)) {
935
+ const allowedFloatingEffects = pipe(
936
+ fiberType(ts, typeChecker)(type, node.expression),
937
+ orElse(() => effectSubtype(ts, typeChecker)(type, node.expression))
938
+ );
939
+ if (isNone2(allowedFloatingEffects)) {
896
940
  effectDiagnostics.push({
897
941
  node,
898
942
  category: ts.DiagnosticCategory.Error,
@@ -968,8 +1012,7 @@ var dedupeWith = /* @__PURE__ */ dual(2, (self, isEquivalent) => {
968
1012
  function getNodesContainingRange(ts) {
969
1013
  return (sourceFile, textRange) => {
970
1014
  const precedingToken = ts.findPrecedingToken(textRange.pos, sourceFile);
971
- if (!precedingToken)
972
- return empty();
1015
+ if (!precedingToken) return empty();
973
1016
  let result = empty();
974
1017
  let parent = precedingToken;
975
1018
  while (parent) {
@@ -989,19 +1032,14 @@ function isNodeInRange(textRange) {
989
1032
  }
990
1033
  function findModuleNamedBindings(ts) {
991
1034
  return (sourceFile, moduleName) => fromNullable(ts.forEachChild(sourceFile, (node) => {
992
- if (!ts.isImportDeclaration(node))
993
- return;
1035
+ if (!ts.isImportDeclaration(node)) return;
994
1036
  const moduleSpecifier = node.moduleSpecifier;
995
- if (!ts.isStringLiteral(moduleSpecifier))
996
- return;
997
- if (moduleSpecifier.text !== moduleName)
998
- return;
1037
+ if (!ts.isStringLiteral(moduleSpecifier)) return;
1038
+ if (moduleSpecifier.text !== moduleName) return;
999
1039
  const importClause = node.importClause;
1000
- if (!importClause)
1001
- return;
1040
+ if (!importClause) return;
1002
1041
  const namedBindings = importClause.namedBindings;
1003
- if (!namedBindings)
1004
- return;
1042
+ if (!namedBindings) return;
1005
1043
  return namedBindings;
1006
1044
  }));
1007
1045
  }
@@ -1010,8 +1048,7 @@ function findModuleNamespaceImportIdentifierName(ts) {
1010
1048
  findModuleNamedBindings(ts)(sourceFile, moduleName),
1011
1049
  map(
1012
1050
  (namedBindings) => {
1013
- if (!ts.isNamespaceImport(namedBindings))
1014
- return;
1051
+ if (!ts.isNamespaceImport(namedBindings)) return;
1015
1052
  return namedBindings.name.text;
1016
1053
  }
1017
1054
  ),
@@ -1022,11 +1059,10 @@ function findModuleNamedImportIdentifierName(ts) {
1022
1059
  return (sourceFile, moduleName, namedImport) => pipe(
1023
1060
  findModuleNamedBindings(ts)(sourceFile, moduleName),
1024
1061
  map((namedBindings) => {
1025
- if (!ts.isNamedImports(namedBindings))
1026
- return;
1062
+ if (!ts.isNamedImports(namedBindings)) return;
1027
1063
  for (const importSpecifier of namedBindings.elements) {
1028
- if (importSpecifier.propertyName?.escapedText === namedImport) {
1029
- return importSpecifier.name?.escapedText || importSpecifier.propertyName?.escapedText;
1064
+ if (importSpecifier.propertyName?.getText() === namedImport) {
1065
+ return importSpecifier.name?.escapedText || importSpecifier.propertyName?.getText();
1030
1066
  }
1031
1067
  }
1032
1068
  }),
@@ -1036,29 +1072,22 @@ function findModuleNamedImportIdentifierName(ts) {
1036
1072
  function findModuleImportIdentifierNameViaTypeChecker(ts, typeChecker) {
1037
1073
  return (sourceFile, importName) => {
1038
1074
  return fromNullable(ts.forEachChild(sourceFile, (node) => {
1039
- if (!ts.isImportDeclaration(node))
1040
- return;
1041
- if (!node.importClause)
1042
- return;
1075
+ if (!ts.isImportDeclaration(node)) return;
1076
+ if (!node.importClause) return;
1043
1077
  const namedBindings = node.importClause.namedBindings;
1044
- if (!namedBindings)
1045
- return;
1078
+ if (!namedBindings) return;
1046
1079
  if (ts.isNamespaceImport(namedBindings)) {
1047
1080
  const symbol3 = typeChecker.getTypeAtLocation(namedBindings).getSymbol();
1048
- if (!symbol3 || !symbol3.exports)
1049
- return;
1050
- if (!symbol3.exports.has(importName))
1051
- return;
1081
+ if (!symbol3 || !symbol3.exports) return;
1082
+ if (!symbol3.exports.has(importName)) return;
1052
1083
  return namedBindings.name.escapedText;
1053
1084
  }
1054
1085
  if (ts.isNamedImports(namedBindings)) {
1055
1086
  for (const importSpecifier of namedBindings.elements) {
1056
1087
  const symbol3 = typeChecker.getTypeAtLocation(importSpecifier).getSymbol();
1057
- if (!symbol3 || !symbol3.exports)
1058
- return;
1059
- if (!symbol3.exports.has(importName))
1060
- return;
1061
- return importSpecifier.name?.escapedText || importSpecifier.propertyName?.escapedText;
1088
+ if (!symbol3 || !symbol3.exports) return;
1089
+ if (!symbol3.exports.has(importName)) return;
1090
+ return importSpecifier.name?.escapedText || importSpecifier.propertyName?.getText();
1062
1091
  }
1063
1092
  }
1064
1093
  }));
@@ -1179,8 +1208,7 @@ function getEffectModuleIdentifier(ts, typeChecker) {
1179
1208
  }
1180
1209
  function simplifyTypeNode(ts) {
1181
1210
  function collectCallable(typeNode) {
1182
- if (ts.isParenthesizedTypeNode(typeNode))
1183
- return collectCallable(typeNode.type);
1211
+ if (ts.isParenthesizedTypeNode(typeNode)) return collectCallable(typeNode.type);
1184
1212
  if (ts.isFunctionTypeNode(typeNode)) {
1185
1213
  return some2([
1186
1214
  ts.factory.createCallSignature(typeNode.typeParameters, typeNode.parameters, typeNode.type)
@@ -1210,23 +1238,18 @@ function simplifyTypeNode(ts) {
1210
1238
  }
1211
1239
  function isPipeCall(ts) {
1212
1240
  return (node) => {
1213
- if (!ts.isCallExpression(node))
1214
- return false;
1241
+ if (!ts.isCallExpression(node)) return false;
1215
1242
  const expression = node.expression;
1216
- if (!ts.isIdentifier(expression))
1217
- return false;
1218
- if (expression.text !== "pipe")
1219
- return false;
1243
+ if (!ts.isIdentifier(expression)) return false;
1244
+ if (expression.text !== "pipe") return false;
1220
1245
  return true;
1221
1246
  };
1222
1247
  }
1223
1248
  function asDataFirstExpression(ts, checker) {
1224
1249
  return (node, self) => {
1225
- if (!ts.isCallExpression(node))
1226
- return none2();
1250
+ if (!ts.isCallExpression(node)) return none2();
1227
1251
  const signature = checker.getResolvedSignature(node);
1228
- if (!signature)
1229
- return none2();
1252
+ if (!signature) return none2();
1230
1253
  const callSignatures = checker.getTypeAtLocation(node.expression).getCallSignatures();
1231
1254
  for (let i = 0; i < callSignatures.length; i++) {
1232
1255
  const callSignature = callSignatures[i];
@@ -1247,10 +1270,8 @@ function deterministicTypeOrder(ts, typeChecker) {
1247
1270
  return make2((a, b) => {
1248
1271
  const aName = typeChecker.typeToString(a);
1249
1272
  const bName = typeChecker.typeToString(b);
1250
- if (aName < bName)
1251
- return -1;
1252
- if (aName > bName)
1253
- return 1;
1273
+ if (aName < bName) return -1;
1274
+ if (aName > bName) return 1;
1254
1275
  return 0;
1255
1276
  });
1256
1277
  }
@@ -1262,8 +1283,7 @@ function getMissingTypeEntriesInTargetType(ts, typeChecker) {
1262
1283
  const toTest = [realType];
1263
1284
  while (toTest.length > 0) {
1264
1285
  const type = toTest.pop();
1265
- if (!type)
1266
- return result;
1286
+ if (!type) return result;
1267
1287
  if (type.isUnion()) {
1268
1288
  toTest.push(...type.types);
1269
1289
  } else {
@@ -1291,14 +1311,12 @@ var missingEffectContext = createDiagnostic({
1291
1311
  expectedType,
1292
1312
  node2
1293
1313
  );
1294
- if (isNone2(expectedEffect))
1295
- continue;
1314
+ if (isNone2(expectedEffect)) continue;
1296
1315
  const realEffect = effectType(ts, typeChecker)(
1297
1316
  realType,
1298
1317
  valueNode
1299
1318
  );
1300
- if (isNone2(realEffect))
1301
- continue;
1319
+ if (isNone2(realEffect)) continue;
1302
1320
  const missingContext = getMissingTypeEntriesInTargetType(
1303
1321
  ts,
1304
1322
  typeChecker
@@ -1337,14 +1355,12 @@ var missingEffectError = createDiagnostic({
1337
1355
  expectedType,
1338
1356
  node2
1339
1357
  );
1340
- if (isNone2(expectedEffect))
1341
- continue;
1358
+ if (isNone2(expectedEffect)) continue;
1342
1359
  const realEffect = effectType(ts, typeChecker)(
1343
1360
  realType,
1344
1361
  valueNode
1345
1362
  );
1346
- if (isNone2(realEffect))
1347
- continue;
1363
+ if (isNone2(realEffect)) continue;
1348
1364
  const missingErrorTypes = getMissingTypeEntriesInTargetType(
1349
1365
  ts,
1350
1366
  typeChecker
@@ -1386,9 +1402,13 @@ var missingStarInYieldEffectGen = createDiagnostic({
1386
1402
  brokenYields.add(node);
1387
1403
  }
1388
1404
  }
1389
- const effectGen2 = effectGen(ts, typeChecker)(node);
1390
- if (isSome2(effectGen2)) {
1391
- ts.forEachChild(effectGen2.value.body, visit(effectGen2.value.functionStar));
1405
+ const effectGenLike = pipe(
1406
+ effectGen(ts, typeChecker)(node),
1407
+ orElse(() => effectFnUntracedGen(ts, typeChecker)(node)),
1408
+ orElse(() => effectFnGen(ts, typeChecker)(node))
1409
+ );
1410
+ if (isSome2(effectGenLike)) {
1411
+ ts.forEachChild(effectGenLike.value.body, visit(effectGenLike.value.functionStar));
1392
1412
  } else if ((ts.isFunctionExpression(node) || ts.isMethodDeclaration(node)) && node.asteriskToken !== void 0) {
1393
1413
  ts.forEachChild(node, visit(void 0));
1394
1414
  } else {
@@ -1760,8 +1780,7 @@ var toggleReturnTypeAnnotation = createRefactor({
1760
1780
  const returnTypeNodes = returnTypes.map(
1761
1781
  (type) => typeChecker.typeToTypeNode(type, node, ts.NodeBuilderFlags.NoTruncation)
1762
1782
  ).filter((node2) => !!node2);
1763
- if (returnTypeNodes.length === 0)
1764
- return;
1783
+ if (returnTypeNodes.length === 0) return;
1765
1784
  const returnTypeNode = returnTypeNodes.length === 1 ? returnTypeNodes[0] : ts.factory.createUnionTypeNode(returnTypeNodes);
1766
1785
  addReturnTypeAnnotation(ts, changeTracker)(
1767
1786
  sourceFile,
@@ -1823,8 +1842,7 @@ var wrapWithPipe = createRefactor({
1823
1842
  name: "effect/wrapWithPipe",
1824
1843
  description: "Wrap with pipe",
1825
1844
  apply: () => (sourceFile, textRange) => {
1826
- if (textRange.end - textRange.pos === 0)
1827
- return none2();
1845
+ if (textRange.end - textRange.pos === 0) return none2();
1828
1846
  return some2({
1829
1847
  kind: "refactor.rewrite.effect.wrapWithPipe",
1830
1848
  description: `Wrap with pipe(...)`,
@@ -1997,4 +2015,4 @@ var init = (modules) => {
1997
2015
  return { create };
1998
2016
  };
1999
2017
  module.exports = init;
2000
- //# sourceMappingURL=index.cjs.map
2018
+ //# sourceMappingURL=index.js.map