@effect/language-service 0.30.0 → 0.31.1

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
@@ -52,6 +52,7 @@ And you're done! You'll now be able to use a set of refactors and diagnostics th
52
52
  - Warn on usage of try/catch inside `Effect.gen` and family
53
53
  - Detect unnecessary pipe chains like `X.pipe(Y).pipe(Z)`
54
54
  - Warn when using `Effect.Service` with `accessors: true` but methods have generics or multiple signatures
55
+ - Warn on missing service dependencies in `Effect.Service` declarations
55
56
 
56
57
  ### Completions
57
58
 
package/cli.js CHANGED
@@ -30562,6 +30562,7 @@ function make64(ts2, tsUtils, typeChecker) {
30562
30562
  );
30563
30563
  if (isSome2(parsedContextTag)) {
30564
30564
  let accessors2 = void 0;
30565
+ let dependencies = void 0;
30565
30566
  if (wholeCall.arguments.length >= 2) {
30566
30567
  const args3 = wholeCall.arguments[1];
30567
30568
  if (ts2.isObjectLiteralExpression(args3)) {
@@ -30569,6 +30570,9 @@ function make64(ts2, tsUtils, typeChecker) {
30569
30570
  if (ts2.isPropertyAssignment(property) && property.name && ts2.isIdentifier(property.name) && property.name.text === "accessors" && property.initializer && property.initializer.kind === ts2.SyntaxKind.TrueKeyword) {
30570
30571
  accessors2 = true;
30571
30572
  }
30573
+ if (ts2.isPropertyAssignment(property) && property.name && ts2.isIdentifier(property.name) && property.name.text === "dependencies" && property.initializer && ts2.isArrayLiteralExpression(property.initializer)) {
30574
+ dependencies = property.initializer.elements;
30575
+ }
30572
30576
  }
30573
30577
  }
30574
30578
  }
@@ -30577,7 +30581,8 @@ function make64(ts2, tsUtils, typeChecker) {
30577
30581
  className: atLocation.name,
30578
30582
  selfTypeNode,
30579
30583
  args: wholeCall.arguments,
30580
- accessors: accessors2
30584
+ accessors: accessors2,
30585
+ dependencies
30581
30586
  };
30582
30587
  }
30583
30588
  }
@@ -31299,6 +31304,89 @@ var missingEffectError = createDiagnostic({
31299
31304
  })
31300
31305
  });
31301
31306
 
31307
+ // src/diagnostics/missingEffectServiceDependency.ts
31308
+ var missingEffectServiceDependency = createDiagnostic({
31309
+ name: "missingEffectServiceDependency",
31310
+ code: 21,
31311
+ severity: "off",
31312
+ apply: fn("missingEffectServiceDependency.apply")(function* (sourceFile, report) {
31313
+ const ts2 = yield* service2(TypeScriptApi);
31314
+ const typeChecker = yield* service2(TypeCheckerApi);
31315
+ const typeParser = yield* service2(TypeParser);
31316
+ const nodeToVisit = [];
31317
+ const appendNodeToVisit = (node) => {
31318
+ nodeToVisit.push(node);
31319
+ return void 0;
31320
+ };
31321
+ ts2.forEachChild(sourceFile, appendNodeToVisit);
31322
+ while (nodeToVisit.length > 0) {
31323
+ const node = nodeToVisit.shift();
31324
+ if (ts2.isClassDeclaration(node) && node.name && node.heritageClauses) {
31325
+ const serviceResult = yield* pipe(
31326
+ typeParser.extendsEffectService(node),
31327
+ orElse14(() => void_8)
31328
+ );
31329
+ if (serviceResult) {
31330
+ const { className, dependencies } = serviceResult;
31331
+ const classSymbol = typeChecker.getSymbolAtLocation(className);
31332
+ if (classSymbol) {
31333
+ const classType = typeChecker.getTypeOfSymbol(classSymbol);
31334
+ const defaultWithoutDepsProperty = typeChecker.getPropertyOfType(classType, "DefaultWithoutDependencies");
31335
+ const defaultProperty = defaultWithoutDepsProperty || typeChecker.getPropertyOfType(classType, "Default");
31336
+ if (defaultProperty) {
31337
+ const defaultType = typeChecker.getTypeOfSymbolAtLocation(defaultProperty, node);
31338
+ const layerResult = yield* pipe(
31339
+ typeParser.layerType(defaultType, node),
31340
+ orElse14(() => void_8)
31341
+ );
31342
+ if (layerResult) {
31343
+ const servicesMemory = /* @__PURE__ */ new Map();
31344
+ const excludeNever = (type2) => succeed17((type2.flags & ts2.TypeFlags.Never) !== 0);
31345
+ const { allIndexes: requiredIndexes } = yield* appendToUniqueTypesMap(
31346
+ servicesMemory,
31347
+ layerResult.RIn,
31348
+ excludeNever
31349
+ );
31350
+ const providedIndexes = /* @__PURE__ */ new Set();
31351
+ const dependenciesToProcess = dependencies || [];
31352
+ for (const depExpression of dependenciesToProcess) {
31353
+ const depType = typeChecker.getTypeAtLocation(depExpression);
31354
+ const depLayerResult = yield* pipe(
31355
+ typeParser.layerType(depType, depExpression),
31356
+ orElse14(() => void_8)
31357
+ );
31358
+ if (depLayerResult) {
31359
+ const { allIndexes } = yield* appendToUniqueTypesMap(
31360
+ servicesMemory,
31361
+ depLayerResult.ROut,
31362
+ excludeNever
31363
+ );
31364
+ for (const index of allIndexes) {
31365
+ providedIndexes.add(index);
31366
+ }
31367
+ }
31368
+ }
31369
+ const missingIndexes = requiredIndexes.filter((index) => !providedIndexes.has(index));
31370
+ if (missingIndexes.length > 0) {
31371
+ const missingTypes = missingIndexes.map((index) => servicesMemory.get(index));
31372
+ const missingTypeNames = missingTypes.map((t) => typeChecker.typeToString(t));
31373
+ const message = missingTypeNames.length === 1 ? `Service '${missingTypeNames[0]}' is required but not provided by dependencies` : `Services ${missingTypeNames.map((s) => `'${s}'`).join(", ")} are required but not provided by dependencies`;
31374
+ report({
31375
+ location: className,
31376
+ messageText: message,
31377
+ fixes: []
31378
+ });
31379
+ }
31380
+ }
31381
+ }
31382
+ }
31383
+ }
31384
+ }
31385
+ ts2.forEachChild(node, appendNodeToVisit);
31386
+ }
31387
+ })
31388
+ });
31389
+
31302
31390
  // src/diagnostics/missingReturnYieldStar.ts
31303
31391
  var missingReturnYieldStar = createDiagnostic({
31304
31392
  name: "missingReturnYieldStar",
@@ -32355,6 +32443,7 @@ var diagnostics = [
32355
32443
  duplicatePackage,
32356
32444
  missingEffectContext,
32357
32445
  missingEffectError,
32446
+ missingEffectServiceDependency,
32358
32447
  floatingEffect,
32359
32448
  missingStarInYieldEffectGen,
32360
32449
  unnecessaryEffectGen,