@effect/language-service 0.31.2 → 0.33.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/index.js CHANGED
@@ -1519,16 +1519,34 @@ function parseDiagnosticSeverity(config) {
1519
1519
  )
1520
1520
  );
1521
1521
  }
1522
+ var defaults = {
1523
+ refactors: true,
1524
+ diagnostics: true,
1525
+ diagnosticSeverity: {},
1526
+ quickinfo: true,
1527
+ quickinfoEffectParameters: "whentruncated",
1528
+ completions: true,
1529
+ goto: true,
1530
+ inlays: true,
1531
+ allowedDuplicatedPackages: [],
1532
+ namespaceImportPackages: [],
1533
+ barrelImportPackages: [],
1534
+ topLevelNamedReexports: "ignore"
1535
+ };
1522
1536
  function parse(config) {
1523
1537
  return {
1524
- diagnostics: isObject(config) && hasProperty(config, "diagnostics") && isBoolean(config.diagnostics) ? config.diagnostics : true,
1525
- diagnosticSeverity: isObject(config) && hasProperty(config, "diagnosticSeverity") && isRecord(config.diagnosticSeverity) ? parseDiagnosticSeverity(config.diagnosticSeverity) : {},
1526
- quickinfo: isObject(config) && hasProperty(config, "quickinfo") && isBoolean(config.quickinfo) ? config.quickinfo : true,
1527
- completions: isObject(config) && hasProperty(config, "completions") && isBoolean(config.completions) ? config.completions : true,
1528
- goto: isObject(config) && hasProperty(config, "goto") && isBoolean(config.goto) ? config.goto : true,
1529
- allowedDuplicatedPackages: isObject(config) && hasProperty(config, "allowedDuplicatedPackages") && isArray(config.allowedDuplicatedPackages) && config.allowedDuplicatedPackages.every(isString) ? config.allowedDuplicatedPackages.map((_) => _.toLowerCase()) : [],
1530
- namespaceImportPackages: isObject(config) && hasProperty(config, "namespaceImportPackages") && isArray(config.namespaceImportPackages) && config.namespaceImportPackages.every(isString) ? config.namespaceImportPackages.map((_) => _.toLowerCase()) : [],
1531
- barrelImportPackages: isObject(config) && hasProperty(config, "barrelImportPackages") && isArray(config.barrelImportPackages) && config.barrelImportPackages.every(isString) ? config.barrelImportPackages.map((_) => _.toLowerCase()) : []
1538
+ refactors: isObject(config) && hasProperty(config, "refactors") && isBoolean(config.refactors) ? config.refactors : defaults.refactors,
1539
+ diagnostics: isObject(config) && hasProperty(config, "diagnostics") && isBoolean(config.diagnostics) ? config.diagnostics : defaults.diagnostics,
1540
+ diagnosticSeverity: isObject(config) && hasProperty(config, "diagnosticSeverity") && isRecord(config.diagnosticSeverity) ? parseDiagnosticSeverity(config.diagnosticSeverity) : defaults.diagnosticSeverity,
1541
+ quickinfo: isObject(config) && hasProperty(config, "quickinfo") && isBoolean(config.quickinfo) ? config.quickinfo : defaults.quickinfo,
1542
+ quickinfoEffectParameters: isObject(config) && hasProperty(config, "quickinfoEffectParameters") && isString(config.quickinfoEffectParameters) && ["always", "never", "whentruncated"].includes(config.quickinfoEffectParameters.toLowerCase()) ? config.quickinfoEffectParameters.toLowerCase() : defaults.quickinfoEffectParameters,
1543
+ completions: isObject(config) && hasProperty(config, "completions") && isBoolean(config.completions) ? config.completions : defaults.completions,
1544
+ goto: isObject(config) && hasProperty(config, "goto") && isBoolean(config.goto) ? config.goto : defaults.goto,
1545
+ inlays: isObject(config) && hasProperty(config, "inlays") && isBoolean(config.inlays) ? config.inlays : defaults.inlays,
1546
+ allowedDuplicatedPackages: isObject(config) && hasProperty(config, "allowedDuplicatedPackages") && isArray(config.allowedDuplicatedPackages) && config.allowedDuplicatedPackages.every(isString) ? config.allowedDuplicatedPackages.map((_) => _.toLowerCase()) : defaults.allowedDuplicatedPackages,
1547
+ namespaceImportPackages: isObject(config) && hasProperty(config, "namespaceImportPackages") && isArray(config.namespaceImportPackages) && config.namespaceImportPackages.every(isString) ? config.namespaceImportPackages.map((_) => _.toLowerCase()) : defaults.namespaceImportPackages,
1548
+ barrelImportPackages: isObject(config) && hasProperty(config, "barrelImportPackages") && isArray(config.barrelImportPackages) && config.barrelImportPackages.every(isString) ? config.barrelImportPackages.map((_) => _.toLowerCase()) : defaults.barrelImportPackages,
1549
+ topLevelNamedReexports: isObject(config) && hasProperty(config, "topLevelNamedReexports") && isString(config.topLevelNamedReexports) && ["ignore", "follow"].includes(config.topLevelNamedReexports.toLowerCase()) ? config.topLevelNamedReexports.toLowerCase() : defaults.topLevelNamedReexports
1532
1550
  };
1533
1551
  }
1534
1552
 
@@ -3599,9 +3617,11 @@ var floatingEffect = createDiagnostic({
3599
3617
  option
3600
3618
  );
3601
3619
  if (isNone2(allowedFloatingEffects)) {
3620
+ const isStrictEffect = yield* option(typeParser.strictEffectType(type, node.expression));
3621
+ const name = isSome2(isStrictEffect) ? "Effect" : "Effect-able " + typeChecker.typeToString(type);
3602
3622
  report({
3603
3623
  location: node,
3604
- messageText: `Effect must be yielded or assigned to a variable.`,
3624
+ messageText: `${name} must be yielded or assigned to a variable.`,
3605
3625
  fixes: []
3606
3626
  });
3607
3627
  }
@@ -4228,7 +4248,7 @@ var missingReturnYieldStar = createDiagnostic({
4228
4248
  }] : [];
4229
4249
  report({
4230
4250
  location: node,
4231
- messageText: `Yielded Effect never succeeds, so it is best to use a 'return yield*' instead.`,
4251
+ messageText: `It is recommended to use return yield* for Effects that never succeed to signal a definitive exit point for type narrowing and tooling support.`,
4232
4252
  fixes: fix
4233
4253
  });
4234
4254
  }
@@ -5307,6 +5327,7 @@ var makeAutoImportProvider = fn("TypeScriptApi")(function* (fromSourceFile) {
5307
5327
  }
5308
5328
  }
5309
5329
  const mapFromBarrelToNamespace = /* @__PURE__ */ new Map();
5330
+ const mapFromBarrelToBarrel = /* @__PURE__ */ new Map();
5310
5331
  const mapFromNamespaceToBarrel = /* @__PURE__ */ new Map();
5311
5332
  const mapFilenameToModuleAlias = /* @__PURE__ */ new Map();
5312
5333
  const mapFilenameToExportExcludes = /* @__PURE__ */ new Map();
@@ -5327,7 +5348,7 @@ var makeAutoImportProvider = fn("TypeScriptApi")(function* (fromSourceFile) {
5327
5348
  mapFilenameToModuleName.set(realPath, absoluteName);
5328
5349
  };
5329
5350
  const collectImportCache = fn("TypeScriptApi")(
5330
- function* (packagePatterns, kind) {
5351
+ function* (packagePatterns, kind, topLevelNamedReexports) {
5331
5352
  for (const packagePattern of packagePatterns) {
5332
5353
  const packageNames = tsUtils.resolveModulePattern(fromSourceFile, packagePattern);
5333
5354
  for (const packageName of packageNames) {
@@ -5377,11 +5398,28 @@ var makeAutoImportProvider = fn("TypeScriptApi")(function* (fromSourceFile) {
5377
5398
  }
5378
5399
  if (isPackageRoot) {
5379
5400
  for (const namedExport of reExports.namedExports) {
5380
- mapFilenameToExportExcludes.set(barrelSourceFile.fileName, [
5381
- ...mapFilenameToExportExcludes.get(barrelSourceFile.fileName) || [],
5382
- namedExport.name
5383
- ]);
5384
- break;
5401
+ if (topLevelNamedReexports === "ignore") {
5402
+ mapFilenameToExportExcludes.set(barrelSourceFile.fileName, [
5403
+ ...mapFilenameToExportExcludes.get(barrelSourceFile.fileName) || [],
5404
+ namedExport.name
5405
+ ]);
5406
+ } else if (topLevelNamedReexports === "follow") {
5407
+ const reexportedFile = ts.resolveModuleName(
5408
+ namedExport.moduleSpecifier.text,
5409
+ barrelSourceFile.fileName,
5410
+ program.getCompilerOptions(),
5411
+ host
5412
+ );
5413
+ if (!reexportedFile) continue;
5414
+ if (!reexportedFile.resolvedModule) continue;
5415
+ mapFromBarrelToBarrel.set(barrelSourceFile.fileName, {
5416
+ ...mapFromBarrelToBarrel.get(barrelSourceFile.fileName) || {},
5417
+ [namedExport.name]: {
5418
+ fileName: reexportedFile.resolvedModule.resolvedFileName,
5419
+ exportName: namedExport.name
5420
+ }
5421
+ });
5422
+ }
5385
5423
  }
5386
5424
  }
5387
5425
  }
@@ -5389,8 +5427,12 @@ var makeAutoImportProvider = fn("TypeScriptApi")(function* (fromSourceFile) {
5389
5427
  }
5390
5428
  }
5391
5429
  );
5392
- yield* collectImportCache(languageServicePluginOptions.namespaceImportPackages, "namespace");
5393
- yield* collectImportCache(languageServicePluginOptions.barrelImportPackages, "barrel");
5430
+ yield* collectImportCache(
5431
+ languageServicePluginOptions.namespaceImportPackages,
5432
+ "namespace",
5433
+ languageServicePluginOptions.topLevelNamedReexports
5434
+ );
5435
+ yield* collectImportCache(languageServicePluginOptions.barrelImportPackages, "barrel", "ignore");
5394
5436
  const resolveModuleName = (fileName) => {
5395
5437
  const fixedModuleName = mapFilenameToModuleName.get(fileName);
5396
5438
  if (fixedModuleName) return fixedModuleName;
@@ -5408,6 +5450,18 @@ var makeAutoImportProvider = fn("TypeScriptApi")(function* (fromSourceFile) {
5408
5450
  const resolve = (exportFileName, exportName) => {
5409
5451
  const excludedExports = mapFilenameToExportExcludes.get(exportFileName);
5410
5452
  if (excludedExports && excludedExports.includes(exportName)) return;
5453
+ const mapToBarrelRewritten = mapFromBarrelToBarrel.get(exportFileName);
5454
+ if (mapToBarrelRewritten && exportName in mapToBarrelRewritten) {
5455
+ const reexportedFile = mapToBarrelRewritten[exportName];
5456
+ if (reexportedFile) {
5457
+ return {
5458
+ _tag: "NamedImport",
5459
+ fileName: reexportedFile.fileName,
5460
+ moduleName: resolveModuleName(reexportedFile.fileName),
5461
+ name: exportName
5462
+ };
5463
+ }
5464
+ }
5411
5465
  const mapToNamespace = mapFromBarrelToNamespace.get(exportFileName);
5412
5466
  if (mapToNamespace && exportName in mapToNamespace) {
5413
5467
  const namespacedFileName = mapToNamespace[exportName];
@@ -5892,6 +5946,64 @@ function goto(applicableGotoDefinition, sourceFile, position) {
5892
5946
  return effectRpcDefinition(applicableGotoDefinition, sourceFile, position);
5893
5947
  }
5894
5948
 
5949
+ // src/inlays/middlewareGenLike.ts
5950
+ var middlewareGenLike = fn("middlewareGenLike")(function* (sourceFile, _span, preferences, inlayHints) {
5951
+ if (!preferences) return inlayHints;
5952
+ if (preferences.includeInlayFunctionLikeReturnTypeHints !== true) return inlayHints;
5953
+ if (!inlayHints) return inlayHints;
5954
+ const tsUtils = yield* service(TypeScriptUtils);
5955
+ const ts = yield* service(TypeScriptApi);
5956
+ const typeParser = yield* service(TypeParser);
5957
+ const typeChecker = yield* service(TypeCheckerApi);
5958
+ const result = [];
5959
+ const parseType = (node) => {
5960
+ return pipe(
5961
+ map3(typeParser.effectGen(node), (_) => {
5962
+ const type = typeChecker.getTypeAtLocation(_.node);
5963
+ const typeString = typeChecker.typeToString(type, _.generatorFunction, ts.TypeFormatFlags.NoTruncation);
5964
+ return { ..._, typeString };
5965
+ }),
5966
+ orElse2(
5967
+ () => map3(pipe(typeParser.effectFnGen(node), orElse2(() => typeParser.effectFnUntracedGen(node))), (_) => {
5968
+ const fnType = typeChecker.getTypeAtLocation(_.node);
5969
+ const types = [];
5970
+ for (const callSig of fnType.getCallSignatures()) {
5971
+ types.push(
5972
+ typeChecker.typeToString(callSig.getReturnType(), _.generatorFunction, ts.TypeFormatFlags.NoTruncation)
5973
+ );
5974
+ }
5975
+ return { ..._, typeString: types.join(" | ") };
5976
+ })
5977
+ )
5978
+ );
5979
+ };
5980
+ for (const inlayHint of inlayHints) {
5981
+ let modifiedInlayHint = inlayHint;
5982
+ if (inlayHint.kind === ts.InlayHintKind.Type) {
5983
+ const node = tsUtils.findNodeAtPositionIncludingTrivia(sourceFile, inlayHint.position - 1);
5984
+ if (node && node.parent) {
5985
+ const possiblyGen = node.parent;
5986
+ yield* pipe(
5987
+ parseType(possiblyGen),
5988
+ map3((_) => {
5989
+ const argsCloseParen = ts.findChildOfKind(_.generatorFunction, ts.SyntaxKind.CloseParenToken, sourceFile);
5990
+ if (argsCloseParen && _.body && inlayHint.position >= argsCloseParen.getEnd() && inlayHint.position <= _.body.getStart(sourceFile)) {
5991
+ const { displayParts: _displayParts, text: _text, ...toKeep } = inlayHint;
5992
+ modifiedInlayHint = {
5993
+ ...toKeep,
5994
+ text: ": " + _.typeString
5995
+ };
5996
+ }
5997
+ }),
5998
+ ignore
5999
+ );
6000
+ }
6001
+ }
6002
+ result.push(modifiedInlayHint);
6003
+ }
6004
+ return result;
6005
+ });
6006
+
5895
6007
  // src/quickinfo/dedupeJsDocs.ts
5896
6008
  var SymbolDisplayPartEq = make((fa, fb) => fa.kind === fb.kind && fa.text === fb.text);
5897
6009
  var JSDocTagInfoEq = make(
@@ -5915,6 +6027,8 @@ function effectTypeArgs(sourceFile, position, quickInfo2) {
5915
6027
  const ts = yield* service(TypeScriptApi);
5916
6028
  const typeChecker = yield* service(TypeCheckerApi);
5917
6029
  const typeParser = yield* service(TypeParser);
6030
+ const options = yield* service(LanguageServicePluginOptions);
6031
+ if (options.quickinfoEffectParameters === "never") return quickInfo2;
5918
6032
  function formatTypeForQuickInfo(channelType, channelName) {
5919
6033
  const stringRepresentation = typeChecker.typeToString(
5920
6034
  channelType,
@@ -5960,7 +6074,7 @@ function effectTypeArgs(sourceFile, position, quickInfo2) {
5960
6074
  type: typeChecker.getTypeAtLocation(adjustedNode),
5961
6075
  atLocation: adjustedNode,
5962
6076
  node: adjustedNode,
5963
- shouldTry: quickInfo2 && ts.displayPartsToString(quickInfo2.displayParts).indexOf("...") > -1
6077
+ shouldTry: options.quickinfoEffectParameters === "always" && quickInfo2 ? true : quickInfo2 && ts.displayPartsToString(quickInfo2.displayParts).indexOf("...") > -1
5964
6078
  };
5965
6079
  }
5966
6080
  const data = getDataForQuickInfo();
@@ -12398,6 +12512,23 @@ var init = (modules) => {
12398
12512
  }
12399
12513
  return applicableDefinition;
12400
12514
  };
12515
+ proxy.provideInlayHints = (fileName, span, preferences, ...args2) => {
12516
+ const applicableInlayHints = languageService.provideInlayHints(fileName, span, preferences, ...args2);
12517
+ if (languageServicePluginOptions.inlays) {
12518
+ const program = languageService.getProgram();
12519
+ if (program) {
12520
+ const sourceFile = program.getSourceFile(fileName);
12521
+ if (sourceFile) {
12522
+ return pipe(
12523
+ middlewareGenLike(sourceFile, span, preferences, applicableInlayHints),
12524
+ runNano(program),
12525
+ getOrElse(() => applicableInlayHints)
12526
+ );
12527
+ }
12528
+ }
12529
+ }
12530
+ return applicableInlayHints;
12531
+ };
12401
12532
  return proxy;
12402
12533
  }
12403
12534
  return { create, onConfigurationChanged };