@effect/language-service 0.30.0 → 0.31.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 +1 -0
- package/cli.js +90 -1
- package/cli.js.map +1 -1
- package/index.js +90 -1
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +90 -1
- package/transform.js.map +1 -1
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,
|