@effect/language-service 0.40.1 → 0.41.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
@@ -61,6 +61,7 @@ And you're done! You'll now be able to use a set of refactors and diagnostics th
61
61
  - Detect unnecessary pipe chains like `X.pipe(Y).pipe(Z)`
62
62
  - Warn when using `Effect.Service` with `accessors: true` but methods have generics or multiple signatures
63
63
  - Warn on missing service dependencies in `Effect.Service` declarations
64
+ - Warn when `Effect.Service` is used with a primitive type instead of an object type
64
65
  - Warn when schema classes override the default constructor behavior
65
66
 
66
67
  ### Completions
@@ -4098,7 +4098,7 @@ var missingEffectError = createDiagnostic({
4098
4098
  // src/diagnostics/missingEffectServiceDependency.ts
4099
4099
  var missingEffectServiceDependency = createDiagnostic({
4100
4100
  name: "missingEffectServiceDependency",
4101
- code: 21,
4101
+ code: 22,
4102
4102
  severity: "off",
4103
4103
  apply: fn("missingEffectServiceDependency.apply")(function* (sourceFile, report) {
4104
4104
  const ts = yield* service(TypeScriptApi);
@@ -4420,6 +4420,96 @@ var multipleEffectProvide = createDiagnostic({
4420
4420
  })
4421
4421
  });
4422
4422
 
4423
+ // src/diagnostics/nonObjectEffectServiceType.ts
4424
+ var nonObjectEffectServiceType = createDiagnostic({
4425
+ name: "nonObjectEffectServiceType",
4426
+ code: 24,
4427
+ severity: "error",
4428
+ apply: fn("nonObjectEffectServiceType.apply")(function* (sourceFile, report) {
4429
+ const ts = yield* service(TypeScriptApi);
4430
+ const typeChecker = yield* service(TypeCheckerApi);
4431
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
4432
+ const typeParser = yield* service(TypeParser);
4433
+ function isPrimitiveType(type) {
4434
+ return typeCheckerUtils.unrollUnionMembers(type).some(
4435
+ (type2) => !!(type2.flags & ts.TypeFlags.String || type2.flags & ts.TypeFlags.Number || type2.flags & ts.TypeFlags.Boolean || type2.flags & ts.TypeFlags.StringLiteral || type2.flags & ts.TypeFlags.NumberLiteral || type2.flags & ts.TypeFlags.BooleanLiteral || type2.flags & ts.TypeFlags.Undefined || type2.flags & ts.TypeFlags.Null)
4436
+ );
4437
+ }
4438
+ const nodeToVisit = [];
4439
+ const appendNodeToVisit = (node) => {
4440
+ nodeToVisit.push(node);
4441
+ return void 0;
4442
+ };
4443
+ ts.forEachChild(sourceFile, appendNodeToVisit);
4444
+ while (nodeToVisit.length > 0) {
4445
+ const node = nodeToVisit.shift();
4446
+ if (ts.isClassDeclaration(node) && node.name && node.heritageClauses) {
4447
+ const serviceResult = yield* pipe(
4448
+ typeParser.extendsEffectService(node),
4449
+ orElse2(() => void_)
4450
+ );
4451
+ if (serviceResult && serviceResult.options && ts.isObjectLiteralExpression(serviceResult.options)) {
4452
+ const options = serviceResult.options;
4453
+ for (const property of options.properties) {
4454
+ if (!ts.isPropertyAssignment(property) || !ts.isIdentifier(property.name)) {
4455
+ continue;
4456
+ }
4457
+ const propertyName = ts.idText(property.name);
4458
+ const propertyValue = property.initializer;
4459
+ const errorToReport = {
4460
+ location: property.name,
4461
+ messageText: "Effect.Service requires the service type to be an object {} and not a primitive type. \nConsider wrapping the value in an object, or manually using Context.Tag or Effect.Tag if you want to use a primitive instead.",
4462
+ fixes: []
4463
+ };
4464
+ if (propertyName === "succeed") {
4465
+ const valueType = typeChecker.getTypeAtLocation(propertyValue);
4466
+ if (isPrimitiveType(valueType)) {
4467
+ report(errorToReport);
4468
+ }
4469
+ } else if (propertyName === "sync") {
4470
+ const valueType = typeChecker.getTypeAtLocation(propertyValue);
4471
+ const signatures = typeChecker.getSignaturesOfType(valueType, ts.SignatureKind.Call);
4472
+ for (const signature of signatures) {
4473
+ const returnType = typeChecker.getReturnTypeOfSignature(signature);
4474
+ if (isPrimitiveType(returnType)) {
4475
+ report(errorToReport);
4476
+ break;
4477
+ }
4478
+ }
4479
+ } else if (propertyName === "effect" || propertyName === "scoped") {
4480
+ const valueType = typeChecker.getTypeAtLocation(propertyValue);
4481
+ const effectResult = yield* pipe(
4482
+ typeParser.effectType(valueType, propertyValue),
4483
+ orElse2(() => void_)
4484
+ );
4485
+ if (effectResult) {
4486
+ if (isPrimitiveType(effectResult.A)) {
4487
+ report(errorToReport);
4488
+ continue;
4489
+ }
4490
+ } else {
4491
+ const signatures = typeChecker.getSignaturesOfType(valueType, ts.SignatureKind.Call);
4492
+ for (const signature of signatures) {
4493
+ const returnType = typeChecker.getReturnTypeOfSignature(signature);
4494
+ const effectReturnResult = yield* pipe(
4495
+ typeParser.effectType(returnType, propertyValue),
4496
+ orElse2(() => void_)
4497
+ );
4498
+ if (effectReturnResult && isPrimitiveType(effectReturnResult.A)) {
4499
+ report(errorToReport);
4500
+ break;
4501
+ }
4502
+ }
4503
+ }
4504
+ }
4505
+ }
4506
+ }
4507
+ }
4508
+ ts.forEachChild(node, appendNodeToVisit);
4509
+ }
4510
+ })
4511
+ });
4512
+
4423
4513
  // src/refactors/writeTagClassAccessors.ts
4424
4514
  var generate = fn("writeTagClassAccessors.generate")(function* (sourceFile, service2, className, atLocation, involvedMembers) {
4425
4515
  const ts = yield* service(TypeScriptApi);
@@ -5334,7 +5424,8 @@ var diagnostics = [
5334
5424
  multipleEffectProvide,
5335
5425
  outdatedEffectCodegen,
5336
5426
  overriddenSchemaConstructor,
5337
- unsupportedServiceAccessors
5427
+ unsupportedServiceAccessors,
5428
+ nonObjectEffectServiceType
5338
5429
  ];
5339
5430
 
5340
5431
  // src/effect-lsp-patch-utils.ts