@effect/language-service 0.84.1 → 0.84.3
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/cli.js +159 -106
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +112 -59
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +112 -59
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +112 -59
- package/transform.js.map +1 -1
package/index.js
CHANGED
|
@@ -3771,10 +3771,42 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
3771
3771
|
if (node.parent && ts.isJsxOpeningElement(node.parent) && node.parent.tagName === node) return;
|
|
3772
3772
|
if (node.parent && ts.isJsxClosingElement(node.parent) && node.parent.tagName === node) return;
|
|
3773
3773
|
if (node.parent && ts.isJsxAttribute(node.parent) && node.parent.name === node) return;
|
|
3774
|
+
if (isInsideTypeOnlyHeritageExpression(node)) return;
|
|
3774
3775
|
if (ts.isExpression(node) || ts.isTypeNode(node)) {
|
|
3775
3776
|
return typeChecker.getTypeAtLocation(node);
|
|
3776
3777
|
}
|
|
3777
3778
|
}
|
|
3779
|
+
function isInsideTypeOnlyHeritageExpression(node) {
|
|
3780
|
+
if (ts.isExpressionWithTypeArguments(node)) {
|
|
3781
|
+
return isTypeOnlyHeritageClause(node.parent);
|
|
3782
|
+
}
|
|
3783
|
+
if (!ts.isIdentifier(node) && !ts.isPropertyAccessExpression(node)) {
|
|
3784
|
+
return false;
|
|
3785
|
+
}
|
|
3786
|
+
for (let current = node.parent; current; current = current.parent) {
|
|
3787
|
+
if (ts.isPropertyAccessExpression(current)) {
|
|
3788
|
+
continue;
|
|
3789
|
+
}
|
|
3790
|
+
if (ts.isExpressionWithTypeArguments(current)) {
|
|
3791
|
+
return isTypeOnlyHeritageClause(current.parent);
|
|
3792
|
+
}
|
|
3793
|
+
return false;
|
|
3794
|
+
}
|
|
3795
|
+
return false;
|
|
3796
|
+
}
|
|
3797
|
+
function isTypeOnlyHeritageClause(node) {
|
|
3798
|
+
if (!node || !ts.isHeritageClause(node)) {
|
|
3799
|
+
return false;
|
|
3800
|
+
}
|
|
3801
|
+
const container = node.parent;
|
|
3802
|
+
if (!container) {
|
|
3803
|
+
return false;
|
|
3804
|
+
}
|
|
3805
|
+
if (ts.isInterfaceDeclaration(container)) {
|
|
3806
|
+
return true;
|
|
3807
|
+
}
|
|
3808
|
+
return ts.isClassLike(container) && node.token === ts.SyntaxKind.ImplementsKeyword;
|
|
3809
|
+
}
|
|
3778
3810
|
function resolveToGlobalSymbol(symbol3) {
|
|
3779
3811
|
if (symbol3.flags & ts.SymbolFlags.Alias) {
|
|
3780
3812
|
symbol3 = typeChecker.getAliasedSymbol(symbol3);
|
|
@@ -4098,6 +4130,14 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
4098
4130
|
),
|
|
4099
4131
|
([A, E, R]) => ({ A, E, R })
|
|
4100
4132
|
);
|
|
4133
|
+
const streamVarianceStruct = (type, atLocation) => map5(
|
|
4134
|
+
all(
|
|
4135
|
+
varianceStructCovariantType(type, atLocation, "_A"),
|
|
4136
|
+
varianceStructCovariantType(type, atLocation, "_E"),
|
|
4137
|
+
varianceStructCovariantType(type, atLocation, "_R")
|
|
4138
|
+
),
|
|
4139
|
+
([A, E, R]) => ({ A, E, R })
|
|
4140
|
+
);
|
|
4101
4141
|
const layerVarianceStruct = (type, atLocation) => map5(
|
|
4102
4142
|
all(
|
|
4103
4143
|
varianceStructContravariantType(type, atLocation, "_ROut"),
|
|
@@ -4144,6 +4184,21 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
4144
4184
|
"TypeParser.strictEffectType",
|
|
4145
4185
|
(type) => type
|
|
4146
4186
|
);
|
|
4187
|
+
const streamType = cachedBy(
|
|
4188
|
+
fn("TypeParser.streamType")(function* (type, atLocation) {
|
|
4189
|
+
if (supportedEffect() === "v3") {
|
|
4190
|
+
return yield* effectType(type, atLocation);
|
|
4191
|
+
}
|
|
4192
|
+
const typeIdSymbol = typeChecker.getPropertyOfType(type, "~effect/Stream");
|
|
4193
|
+
if (!typeIdSymbol) {
|
|
4194
|
+
return yield* typeParserIssue("Type is not a stream", type, atLocation);
|
|
4195
|
+
}
|
|
4196
|
+
const typeIdType = typeChecker.getTypeOfSymbolAtLocation(typeIdSymbol, atLocation);
|
|
4197
|
+
return yield* streamVarianceStruct(typeIdType, atLocation);
|
|
4198
|
+
}),
|
|
4199
|
+
"TypeParser.streamType",
|
|
4200
|
+
(type) => type
|
|
4201
|
+
);
|
|
4147
4202
|
const isEffectTypeSourceFile = cachedBy(
|
|
4148
4203
|
fn("TypeParser.isEffectTypeSourceFile")(function* (sourceFile) {
|
|
4149
4204
|
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
@@ -5879,6 +5934,7 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
5879
5934
|
isServiceMapTypeSourceFile,
|
|
5880
5935
|
isNodeReferenceToServiceMapModuleApi,
|
|
5881
5936
|
effectType,
|
|
5937
|
+
streamType,
|
|
5882
5938
|
strictEffectType,
|
|
5883
5939
|
layerType,
|
|
5884
5940
|
fiberType,
|
|
@@ -7337,7 +7393,7 @@ var catchAllToMapError = createDiagnostic({
|
|
|
7337
7393
|
const { failArg, failCall } = failCallInfo;
|
|
7338
7394
|
report({
|
|
7339
7395
|
location: transformation.callee,
|
|
7340
|
-
messageText:
|
|
7396
|
+
messageText: `\`Effect.mapError\` expresses the same error-type transformation more directly than \`Effect.${catchAllName}\` followed by \`Effect.fail\`.`,
|
|
7341
7397
|
fixes: [{
|
|
7342
7398
|
fixName: "catchAllToMapError_fix",
|
|
7343
7399
|
description: "Replace with Effect.mapError",
|
|
@@ -7401,7 +7457,7 @@ var catchUnfailableEffect = createDiagnostic({
|
|
|
7401
7457
|
if (E.flags & ts.TypeFlags.Never) {
|
|
7402
7458
|
report({
|
|
7403
7459
|
location: transformation.callee,
|
|
7404
|
-
messageText:
|
|
7460
|
+
messageText: "The previous Effect does not fail, so this error-handling branch will never run.",
|
|
7405
7461
|
fixes: []
|
|
7406
7462
|
});
|
|
7407
7463
|
}
|
|
@@ -7464,7 +7520,7 @@ var classSelfMismatch = createDiagnostic({
|
|
|
7464
7520
|
if (actualName !== expectedName) {
|
|
7465
7521
|
report({
|
|
7466
7522
|
location: selfTypeNode,
|
|
7467
|
-
messageText: `Self type parameter should be
|
|
7523
|
+
messageText: `The \`Self\` type parameter for this class should be \`${expectedName}\`.`,
|
|
7468
7524
|
fixes: [{
|
|
7469
7525
|
fixName: "classSelfMismatch_fix",
|
|
7470
7526
|
description: `Replace '${actualName}' with '${expectedName}'`,
|
|
@@ -7588,7 +7644,7 @@ var deterministicKeys = createDiagnostic({
|
|
|
7588
7644
|
if (actualIdentifier !== expectedKey) {
|
|
7589
7645
|
report({
|
|
7590
7646
|
location: keyStringLiteral,
|
|
7591
|
-
messageText: `
|
|
7647
|
+
messageText: `This key does not match the deterministic key for this declaration. The expected key is \`${expectedKey}\`.`,
|
|
7592
7648
|
fixes: [{
|
|
7593
7649
|
fixName: "deterministicKeys_fix",
|
|
7594
7650
|
description: `Replace '${actualIdentifier}' with '${expectedKey}'`,
|
|
@@ -7627,9 +7683,8 @@ var duplicatePackage = createDiagnostic({
|
|
|
7627
7683
|
const versions = Object.keys(resolvedPackages[packageName]);
|
|
7628
7684
|
report({
|
|
7629
7685
|
location: sourceFile.statements[0],
|
|
7630
|
-
messageText: `
|
|
7631
|
-
|
|
7632
|
-
If this is intended set the LSP config "allowedDuplicatedPackages" to ${JSON.stringify(options.allowedDuplicatedPackages.concat([packageName]))}.
|
|
7686
|
+
messageText: `Multiple versions of package \`${packageName}\` were detected: ${versions.join(", ")}. Package duplication can change runtime identity and type equality across Effect modules.
|
|
7687
|
+
If this is intentional, set the LSP config \`allowedDuplicatedPackages\` to ${JSON.stringify(options.allowedDuplicatedPackages.concat([packageName]))}.
|
|
7633
7688
|
|
|
7634
7689
|
${versions.map((version) => `- found ${version} at ${resolvedPackages[packageName][version]}`).join("\n")}`,
|
|
7635
7690
|
fixes: []
|
|
@@ -7737,7 +7792,7 @@ var effectFnIife = createDiagnostic({
|
|
|
7737
7792
|
const traceExpressionText = traceExpression ? sourceFile.text.slice(traceExpression.pos, traceExpression.end) : void 0;
|
|
7738
7793
|
report({
|
|
7739
7794
|
location: node,
|
|
7740
|
-
messageText:
|
|
7795
|
+
messageText: `\`${effectModuleName}.${kind}\` returns a reusable function that can take arguments, but it is invoked immediately here. \`Effect.gen\` represents the immediate-use form for this pattern${traceExpressionText ? ` with \`Effect.withSpan(${traceExpressionText})\` piped at the end to maintain tracing spans` : ``}.`,
|
|
7741
7796
|
fixes
|
|
7742
7797
|
});
|
|
7743
7798
|
}
|
|
@@ -7822,7 +7877,7 @@ var effectFnImplicitAny = createDiagnostic({
|
|
|
7822
7877
|
const parameterName = getParameterName(ts, parameter.name);
|
|
7823
7878
|
report({
|
|
7824
7879
|
location: parameter.name,
|
|
7825
|
-
messageText: `Parameter
|
|
7880
|
+
messageText: `Parameter \`${parameterName}\` implicitly has type \`any\` in \`Effect.fn\`, \`Effect.fnUntraced\`, or \`Effect.fnUntracedEager\`. No parameter type is available from an explicit annotation or contextual function type.`,
|
|
7826
7881
|
fixes: []
|
|
7827
7882
|
});
|
|
7828
7883
|
}
|
|
@@ -8418,7 +8473,7 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
8418
8473
|
const expectedSignature = generateExpectedSignature();
|
|
8419
8474
|
report({
|
|
8420
8475
|
location: nameIdentifier ?? targetNode,
|
|
8421
|
-
messageText: `
|
|
8476
|
+
messageText: `This expression can be rewritten in the reusable function form \`${expectedSignature}\`.`,
|
|
8422
8477
|
fixes
|
|
8423
8478
|
});
|
|
8424
8479
|
}
|
|
@@ -8630,7 +8685,7 @@ var effectMapVoid = createDiagnostic({
|
|
|
8630
8685
|
if (isNone2(match2)) continue;
|
|
8631
8686
|
report({
|
|
8632
8687
|
location: node.expression,
|
|
8633
|
-
messageText: "
|
|
8688
|
+
messageText: "This expression discards the success value through mapping. `Effect.asVoid` represents that form directly.",
|
|
8634
8689
|
fixes: [{
|
|
8635
8690
|
fixName: "effectMapVoid_fix",
|
|
8636
8691
|
description: "Replace with Effect.asVoid",
|
|
@@ -8685,7 +8740,7 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
8685
8740
|
if (!tsUtils.isVoidExpression(argument)) continue;
|
|
8686
8741
|
report({
|
|
8687
8742
|
location: node,
|
|
8688
|
-
messageText: "Effect.void
|
|
8743
|
+
messageText: "`Effect.void` represents the same outcome as `Effect.succeed(undefined)` or `Effect.succeed(void 0)`.",
|
|
8689
8744
|
fixes: [{
|
|
8690
8745
|
fixName: "effectSucceedWithVoid_fix",
|
|
8691
8746
|
description: "Replace with Effect.void",
|
|
@@ -8747,7 +8802,7 @@ var extendsNativeError = createDiagnostic({
|
|
|
8747
8802
|
if (isNativeError) {
|
|
8748
8803
|
report({
|
|
8749
8804
|
location: node.name ?? typeExpression,
|
|
8750
|
-
messageText: "
|
|
8805
|
+
messageText: "This class extends the native `Error` type directly. Untagged native errors lose distinction in the Effect failure channel.",
|
|
8751
8806
|
fixes: []
|
|
8752
8807
|
});
|
|
8753
8808
|
}
|
|
@@ -8792,7 +8847,12 @@ var floatingEffect = createDiagnostic({
|
|
|
8792
8847
|
if (!isFloatingExpression(node)) continue;
|
|
8793
8848
|
const type = typeCheckerUtils.getTypeAtLocation(node.expression);
|
|
8794
8849
|
if (!type) continue;
|
|
8795
|
-
const effect = yield* option(
|
|
8850
|
+
const effect = yield* option(
|
|
8851
|
+
pipe(
|
|
8852
|
+
typeParser.effectType(type, node.expression),
|
|
8853
|
+
orElse2(() => typeParser.streamType(type, node.expression))
|
|
8854
|
+
)
|
|
8855
|
+
);
|
|
8796
8856
|
if (isSome2(effect)) {
|
|
8797
8857
|
const allowedFloatingEffects = yield* pipe(
|
|
8798
8858
|
typeParser.fiberType(type, node.expression),
|
|
@@ -8801,10 +8861,9 @@ var floatingEffect = createDiagnostic({
|
|
|
8801
8861
|
);
|
|
8802
8862
|
if (isNone2(allowedFloatingEffects)) {
|
|
8803
8863
|
const isStrictEffect = yield* option(typeParser.strictEffectType(type, node.expression));
|
|
8804
|
-
const name = isSome2(isStrictEffect) ? "Effect" : "Effect-able " + typeChecker.typeToString(type);
|
|
8805
8864
|
report({
|
|
8806
8865
|
location: node,
|
|
8807
|
-
messageText:
|
|
8866
|
+
messageText: isSome2(isStrictEffect) ? "This Effect value is neither yielded nor used in an assignment." : `This Effect-able \`${typeChecker.typeToString(type)}\` value is neither yielded nor assigned to a variable.`,
|
|
8808
8867
|
fixes: []
|
|
8809
8868
|
});
|
|
8810
8869
|
}
|
|
@@ -8899,7 +8958,7 @@ var makeGlobalConsoleApply = (checkInEffect) => fn(`globalConsole${checkInEffect
|
|
|
8899
8958
|
if (inEffect !== checkInEffect) continue;
|
|
8900
8959
|
report({
|
|
8901
8960
|
location: node,
|
|
8902
|
-
messageText: checkInEffect ? `
|
|
8961
|
+
messageText: checkInEffect ? `This Effect code uses \`console.${method}\`, logging in Effect code is represented through \`${alternative}\`.` : `This code uses \`console.${method}\`, the corresponding Effect logging API is \`${alternative}\`.`,
|
|
8903
8962
|
fixes: []
|
|
8904
8963
|
});
|
|
8905
8964
|
}
|
|
@@ -8948,10 +9007,10 @@ var makeGlobalDateApply = (checkInEffect) => fn(`globalDate${checkInEffect ? "In
|
|
|
8948
9007
|
let objectNode;
|
|
8949
9008
|
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.idText(node.expression.name) === "now") {
|
|
8950
9009
|
objectNode = node.expression.expression;
|
|
8951
|
-
messageText = checkInEffect ? "
|
|
9010
|
+
messageText = checkInEffect ? "This Effect code uses `Date.now()`, time access in Effect code is represented through `Clock` from Effect." : "This code uses `Date.now()`, time access is represented through `Clock` from Effect.";
|
|
8952
9011
|
} else if (ts.isNewExpression(node)) {
|
|
8953
9012
|
objectNode = node.expression;
|
|
8954
|
-
messageText = checkInEffect ? "
|
|
9013
|
+
messageText = checkInEffect ? "This Effect code constructs `new Date()`, date values in Effect code are represented through `DateTime` from Effect." : "This code constructs `new Date()`, date values are represented through `DateTime` from Effect.";
|
|
8955
9014
|
}
|
|
8956
9015
|
if (!messageText || !objectNode) continue;
|
|
8957
9016
|
const symbol3 = typeChecker.getSymbolAtLocation(objectNode);
|
|
@@ -9034,7 +9093,7 @@ var globalErrorInEffectCatch = createDiagnostic({
|
|
|
9034
9093
|
);
|
|
9035
9094
|
report({
|
|
9036
9095
|
location: node.expression,
|
|
9037
|
-
messageText: `The
|
|
9096
|
+
messageText: `The \`catch\` callback in \`${nodeText}\` returns the global \`Error\` type. Untagged errors merge together in the Effect error channel and lose type-level distinction; a tagged error preserves that distinction and can wrap the original error in a \`cause\` property.`,
|
|
9038
9097
|
fixes: []
|
|
9039
9098
|
});
|
|
9040
9099
|
}
|
|
@@ -9114,7 +9173,7 @@ var makeGlobalFetchApply = (checkInEffect) => fn(`globalFetch${checkInEffect ? "
|
|
|
9114
9173
|
if (!fetchSymbol) return;
|
|
9115
9174
|
const effectVersion = typeParser.supportedEffect();
|
|
9116
9175
|
const packageName = effectVersion === "v3" ? "@effect/platform" : "effect/unstable/http";
|
|
9117
|
-
const messageText = checkInEffect ? `
|
|
9176
|
+
const messageText = checkInEffect ? `This Effect code calls the global \`fetch\` function, HTTP requests in Effect code are represented through \`HttpClient\` from \`${packageName}\`.` : `This code uses the global \`fetch\` function, HTTP requests are represented through \`HttpClient\` from \`${packageName}\`.`;
|
|
9118
9177
|
const nodeToVisit = [];
|
|
9119
9178
|
const appendNodeToVisit = (node) => {
|
|
9120
9179
|
nodeToVisit.push(node);
|
|
@@ -9187,7 +9246,7 @@ var makeGlobalRandomApply = (checkInEffect) => fn(`globalRandom${checkInEffect ?
|
|
|
9187
9246
|
if (inEffect !== checkInEffect) continue;
|
|
9188
9247
|
report({
|
|
9189
9248
|
location: node,
|
|
9190
|
-
messageText: checkInEffect ? "
|
|
9249
|
+
messageText: checkInEffect ? "This Effect code uses `Math.random()`, randomness is represented through the Effect `Random` service." : "This code uses `Math.random()`, randomness is represented through the Effect `Random` service.",
|
|
9191
9250
|
fixes: []
|
|
9192
9251
|
});
|
|
9193
9252
|
}
|
|
@@ -9218,12 +9277,12 @@ var globalRandom = createDiagnostic({
|
|
|
9218
9277
|
// src/diagnostics/globalTimersInEffect.ts
|
|
9219
9278
|
var timerAlternatives = {
|
|
9220
9279
|
"setTimeout": {
|
|
9221
|
-
inEffect: "
|
|
9222
|
-
outsideEffect: "
|
|
9280
|
+
inEffect: "This Effect code uses `setTimeout`, the corresponding timer API in this context is `Effect.sleep or Schedule` from Effect.",
|
|
9281
|
+
outsideEffect: "This code uses `setTimeout`, the corresponding Effect timer API is `Effect.sleep or Schedule` from Effect."
|
|
9223
9282
|
},
|
|
9224
9283
|
"setInterval": {
|
|
9225
|
-
inEffect: "
|
|
9226
|
-
outsideEffect: "
|
|
9284
|
+
inEffect: "This Effect code uses `setInterval`, the corresponding timer API in this context is `Schedule or Effect.repeat` from Effect.",
|
|
9285
|
+
outsideEffect: "This code uses `setInterval`, the corresponding Effect timer API is `Schedule or Effect.repeat` from Effect."
|
|
9227
9286
|
}
|
|
9228
9287
|
};
|
|
9229
9288
|
var makeGlobalTimersApply = (checkInEffect) => fn(`globalTimers${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
@@ -9465,7 +9524,7 @@ var instanceOfSchema = createDiagnostic({
|
|
|
9465
9524
|
if (isSchemaType._tag === "Some") {
|
|
9466
9525
|
report({
|
|
9467
9526
|
location: node,
|
|
9468
|
-
messageText: "
|
|
9527
|
+
messageText: "This code uses `instanceof` with an Effect Schema type. `Schema.is` is the schema-aware runtime check for this case.",
|
|
9469
9528
|
fixes: [{
|
|
9470
9529
|
fixName: "instanceOfSchema_fix",
|
|
9471
9530
|
description: "Replace with Schema.is",
|
|
@@ -9735,7 +9794,7 @@ var leakingRequirements = createDiagnostic({
|
|
|
9735
9794
|
location: node,
|
|
9736
9795
|
messageText: `Methods of this Service require \`${requirementsStr}\` from every caller.
|
|
9737
9796
|
|
|
9738
|
-
|
|
9797
|
+
The requirement becomes part of the public service surface instead of remaining internal to Layer implementation.
|
|
9739
9798
|
|
|
9740
9799
|
Resolve these dependencies at Layer creation and provide them to each method, so the service's type reflects its purpose, not its implementation.
|
|
9741
9800
|
|
|
@@ -9932,7 +9991,7 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
9932
9991
|
).trim() : "";
|
|
9933
9992
|
report({
|
|
9934
9993
|
location: flow2.node,
|
|
9935
|
-
messageText: `
|
|
9994
|
+
messageText: `This nested call structure has a pipeable form. \`${subjectText}.pipe(...)\` represents the same call sequence in pipe style and may be easier to read.`,
|
|
9936
9995
|
fixes: [{
|
|
9937
9996
|
fixName: "missedPipeableOpportunity_fix",
|
|
9938
9997
|
description: "Convert to pipe style",
|
|
@@ -10013,7 +10072,7 @@ var missingEffectContext = createDiagnostic({
|
|
|
10013
10072
|
(missingTypes) => missingTypes.length > 0 ? report(
|
|
10014
10073
|
{
|
|
10015
10074
|
location: node,
|
|
10016
|
-
messageText: `
|
|
10075
|
+
messageText: `This Effect requires a service that is missing from the expected Effect context: \`${sortTypes(missingTypes).map((_) => typeChecker.typeToString(_)).join(" | ")}\`.`,
|
|
10017
10076
|
fixes: []
|
|
10018
10077
|
}
|
|
10019
10078
|
) : void 0
|
|
@@ -10364,7 +10423,7 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
10364
10423
|
}];
|
|
10365
10424
|
report({
|
|
10366
10425
|
location: unwrapped,
|
|
10367
|
-
messageText:
|
|
10426
|
+
messageText: "This Effect never succeeds; using `return yield*` preserves a definitive generator exit point for type narrowing and tooling support.",
|
|
10368
10427
|
fixes: fix
|
|
10369
10428
|
});
|
|
10370
10429
|
}
|
|
@@ -10420,7 +10479,7 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
10420
10479
|
brokenGenerators.forEach(
|
|
10421
10480
|
(pos) => report({
|
|
10422
10481
|
location: { pos, end: pos + "function".length },
|
|
10423
|
-
messageText: `
|
|
10482
|
+
messageText: "This uses `yield` for an `Effect` value. `yield*` is the Effect-aware form in this context.",
|
|
10424
10483
|
fixes: []
|
|
10425
10484
|
})
|
|
10426
10485
|
);
|
|
@@ -10442,7 +10501,7 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
10442
10501
|
}] : [];
|
|
10443
10502
|
report({
|
|
10444
10503
|
location: node,
|
|
10445
|
-
messageText: `
|
|
10504
|
+
messageText: "This uses `yield` for an `Effect` value. `yield*` is the Effect-aware form in this context.",
|
|
10446
10505
|
fixes: fix
|
|
10447
10506
|
});
|
|
10448
10507
|
});
|
|
@@ -10510,7 +10569,7 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
10510
10569
|
if (chunk.length < 2) continue;
|
|
10511
10570
|
report({
|
|
10512
10571
|
location: chunk[0].node,
|
|
10513
|
-
messageText: "
|
|
10572
|
+
messageText: "This expression chains multiple `Effect.provide` calls. Providing Layers in multiple calls in a chain can break service lifecycle behavior compared with a single combined provide with merged layers.",
|
|
10514
10573
|
fixes: [{
|
|
10515
10574
|
fixName: "multipleEffectProvide_fix",
|
|
10516
10575
|
description: "Combine into a single provide",
|
|
@@ -10600,7 +10659,7 @@ var nodeBuiltinImport = createDiagnostic({
|
|
|
10600
10659
|
if (match2) {
|
|
10601
10660
|
report({
|
|
10602
10661
|
location: statement.moduleSpecifier,
|
|
10603
|
-
messageText: `
|
|
10662
|
+
messageText: `This module reference uses the \`${match2.module}\` module, the corresponding Effect API is \`${match2.alternative}\` from \`${match2.package}\`.`,
|
|
10604
10663
|
fixes: []
|
|
10605
10664
|
});
|
|
10606
10665
|
}
|
|
@@ -10613,7 +10672,7 @@ var nodeBuiltinImport = createDiagnostic({
|
|
|
10613
10672
|
if (match2) {
|
|
10614
10673
|
report({
|
|
10615
10674
|
location: arg,
|
|
10616
|
-
messageText: `
|
|
10675
|
+
messageText: `This module reference uses the \`${match2.module}\` module, the corresponding Effect API is \`${match2.alternative}\` from \`${match2.package}\`.`,
|
|
10617
10676
|
fixes: []
|
|
10618
10677
|
});
|
|
10619
10678
|
}
|
|
@@ -10667,7 +10726,7 @@ var nonObjectEffectServiceType = createDiagnostic({
|
|
|
10667
10726
|
const propertyValue = property.initializer;
|
|
10668
10727
|
const errorToReport = {
|
|
10669
10728
|
location: property.name,
|
|
10670
|
-
messageText: "Effect.Service
|
|
10729
|
+
messageText: "`Effect.Service` is declared with a primitive service type. `Effect.Service` models object-shaped services; primitive values use `Context.Tag` or `Effect.Tag` directly.",
|
|
10671
10730
|
fixes: []
|
|
10672
10731
|
};
|
|
10673
10732
|
if (propertyName === "succeed") {
|
|
@@ -11429,7 +11488,7 @@ var outdatedApi = createDiagnostic({
|
|
|
11429
11488
|
hasReported = true;
|
|
11430
11489
|
report({
|
|
11431
11490
|
location: propertyAccess.name,
|
|
11432
|
-
messageText:
|
|
11491
|
+
messageText: `This project targets Effect v4, but this code uses the Effect v3 API \`${propertyName}\`. The referenced API belongs to the v3 surface rather than the configured v4 surface.`,
|
|
11433
11492
|
fixes: []
|
|
11434
11493
|
});
|
|
11435
11494
|
}
|
|
@@ -11472,7 +11531,7 @@ var outdatedApi = createDiagnostic({
|
|
|
11472
11531
|
if (hasReported) {
|
|
11473
11532
|
report({
|
|
11474
11533
|
location: { pos: 0, end: 0 },
|
|
11475
|
-
messageText: "This project targets Effect v4, but
|
|
11534
|
+
messageText: "This project targets Effect v4, but this code uses Effect v3 APIs. The referenced API belongs to the v3 surface rather than the configured v4 surface.",
|
|
11476
11535
|
fixes: []
|
|
11477
11536
|
});
|
|
11478
11537
|
}
|
|
@@ -11648,7 +11707,7 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
11648
11707
|
};
|
|
11649
11708
|
report({
|
|
11650
11709
|
location: member,
|
|
11651
|
-
messageText: "
|
|
11710
|
+
messageText: "This Schema subclass defines its own constructor. For Schema classes, constructor overrides break decoding behavior for the class shape. Custom construction can be expressed through a static `new` method instead.",
|
|
11652
11711
|
fixes: (member.body ? [fixAsStaticNew] : []).concat([{
|
|
11653
11712
|
fixName: "overriddenSchemaConstructor_fix",
|
|
11654
11713
|
description: "Remove the constructor override",
|
|
@@ -11770,7 +11829,7 @@ var preferSchemaOverJson = createDiagnostic({
|
|
|
11770
11829
|
if (isSome2(match2)) {
|
|
11771
11830
|
report({
|
|
11772
11831
|
location: match2.value,
|
|
11773
|
-
messageText: "
|
|
11832
|
+
messageText: "This code uses `JSON.parse` or `JSON.stringify`. Effect Schema provides Effect-aware APIs for JSON parsing and stringifying.",
|
|
11774
11833
|
fixes: []
|
|
11775
11834
|
});
|
|
11776
11835
|
}
|
|
@@ -11888,9 +11947,7 @@ var returnEffectInGen = createDiagnostic({
|
|
|
11888
11947
|
}] : [];
|
|
11889
11948
|
report({
|
|
11890
11949
|
location: node,
|
|
11891
|
-
messageText:
|
|
11892
|
-
Maybe you wanted to return yield* instead?
|
|
11893
|
-
Nested Effect-able types may be intended if you plan to later manually flatten or unwrap this Effect, if so you can safely disable this diagnostic for this line through quickfixes.`,
|
|
11950
|
+
messageText: "This generator returns an Effect-able value directly, which produces a nested `Effect<Effect<...>>`. If the intended result is the inner Effect value, `return yield*` represents that form.",
|
|
11894
11951
|
fixes: fix
|
|
11895
11952
|
});
|
|
11896
11953
|
}),
|
|
@@ -12045,9 +12102,7 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
12045
12102
|
);
|
|
12046
12103
|
});
|
|
12047
12104
|
const v4MethodName = `${isEffectRunCall.value.methodName}With`;
|
|
12048
|
-
const messageText = supportedEffect === "v4" ?
|
|
12049
|
-
Consider extracting the current services by using for example Effect.services and then use Effect.${v4MethodName} with the extracted services instead.` : `Using ${nodeText} inside an Effect is not recommended. The same runtime should generally be used instead to run child effects.
|
|
12050
|
-
Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`;
|
|
12105
|
+
const messageText = supportedEffect === "v4" ? `\`${nodeText}\` is called inside an Effect with a separate services invocation. In this context, child Effects run with the surrounding services, which can be accessed through \`Effect.services\` and \`Effect.${v4MethodName}\`.` : `\`${nodeText}\` is called inside an Effect with a separate runtime invocation. In this context, run child Effects with the surrounding runtime, which can be accessed through \`Effect.runtime\` and \`Runtime.${isEffectRunCall.value.methodName}\`.`;
|
|
12051
12106
|
report({
|
|
12052
12107
|
location: node.expression,
|
|
12053
12108
|
messageText,
|
|
@@ -12060,7 +12115,7 @@ Consider extracting the Runtime by using for example Effect.runtime and then use
|
|
|
12060
12115
|
} else {
|
|
12061
12116
|
report({
|
|
12062
12117
|
location: node.expression,
|
|
12063
|
-
messageText:
|
|
12118
|
+
messageText: `\`${nodeText}\` is called inside an existing Effect context. Here, the inner Effect can be used directly.`,
|
|
12064
12119
|
fixes: []
|
|
12065
12120
|
});
|
|
12066
12121
|
}
|
|
@@ -12115,7 +12170,7 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
12115
12170
|
const otherProperties = arg.properties.filter((prop) => prop !== tagProperty);
|
|
12116
12171
|
report({
|
|
12117
12172
|
location: node,
|
|
12118
|
-
messageText: "Schema.Struct
|
|
12173
|
+
messageText: "This `Schema.Struct` includes a `_tag` field. `Schema.TaggedStruct` is the tagged-struct form for this pattern and makes the tag optional in the constructor.",
|
|
12119
12174
|
fixes: [{
|
|
12120
12175
|
fixName: "schemaStructWithTag_fix",
|
|
12121
12176
|
description: "Replace with Schema.TaggedStruct",
|
|
@@ -12208,7 +12263,7 @@ var schemaSyncInEffect = createDiagnostic({
|
|
|
12208
12263
|
const effectMethodName = syncToEffectMethod[isSchemaSyncCall.value.methodName];
|
|
12209
12264
|
report({
|
|
12210
12265
|
location: node.expression,
|
|
12211
|
-
messageText:
|
|
12266
|
+
messageText: `\`${nodeText}\` is used inside an Effect generator. \`Schema.${effectMethodName}\` preserves the typed Effect error channel for this operation without throwing.`,
|
|
12212
12267
|
fixes: []
|
|
12213
12268
|
});
|
|
12214
12269
|
}
|
|
@@ -12268,7 +12323,7 @@ var schemaUnionOfLiterals = createDiagnostic({
|
|
|
12268
12323
|
const schemaLiteralExpression = firstLiteralCall.expression;
|
|
12269
12324
|
report({
|
|
12270
12325
|
location: node,
|
|
12271
|
-
messageText: "
|
|
12326
|
+
messageText: "This `Schema.Union` contains multiple `Schema.Literal` members and can be simplified to a single `Schema.Literal` call.",
|
|
12272
12327
|
fixes: [{
|
|
12273
12328
|
fixName: "schemaUnionOfLiterals_fix",
|
|
12274
12329
|
description: "Replace with a single Schema.Literal call",
|
|
@@ -12331,8 +12386,7 @@ var scopeInLayerEffect = createDiagnostic({
|
|
|
12331
12386
|
map5(
|
|
12332
12387
|
() => report({
|
|
12333
12388
|
location: node,
|
|
12334
|
-
messageText: `
|
|
12335
|
-
Consider using "scoped" instead to get rid of the scope in the requirements.`,
|
|
12389
|
+
messageText: "This layer construction leaves `Scope` in the requirement set. The scoped API removes `Scope` from the resulting requirements.",
|
|
12336
12390
|
fixes: methodIdentifier ? [{
|
|
12337
12391
|
fixName: "scopeInLayerEffect_scoped",
|
|
12338
12392
|
description: "Use scoped for Layer creation",
|
|
@@ -12432,7 +12486,7 @@ var serviceNotAsClass = createDiagnostic({
|
|
|
12432
12486
|
const shapeText = typeArgs.length > 0 ? typeArgs.map((t) => sourceFile.text.substring(ts.getTokenPosOfNode(t, sourceFile), t.end)).join(", ") : "Shape";
|
|
12433
12487
|
report({
|
|
12434
12488
|
location: callExpr,
|
|
12435
|
-
messageText:
|
|
12489
|
+
messageText: `\`ServiceMap.Service\` is assigned to a variable here, but this API is intended for a class declaration shape such as \`class ${variableName} extends ServiceMap.Service<${variableName}, ${shapeText}>()("${argsText.replace(/['"]/g, "")}") {}\`.`,
|
|
12436
12490
|
fixes: [{
|
|
12437
12491
|
fixName: "serviceNotAsClass",
|
|
12438
12492
|
description: `Convert to class declaration`,
|
|
@@ -12645,7 +12699,7 @@ var tryCatchInEffectGen = createDiagnostic({
|
|
|
12645
12699
|
map5(() => {
|
|
12646
12700
|
report({
|
|
12647
12701
|
location: node,
|
|
12648
|
-
messageText: `
|
|
12702
|
+
messageText: `This Effect generator contains \`try/catch\`; in this context, error handling is expressed with Effect APIs such as ${alternatives.join(", ")}).`,
|
|
12649
12703
|
fixes: []
|
|
12650
12704
|
});
|
|
12651
12705
|
}),
|
|
@@ -12706,8 +12760,7 @@ var unknownInEffectCatch = createDiagnostic({
|
|
|
12706
12760
|
);
|
|
12707
12761
|
report({
|
|
12708
12762
|
location: node.expression,
|
|
12709
|
-
messageText: `The
|
|
12710
|
-
Consider wrapping unknown errors into Effect's Data.TaggedError for example, or narrow down the type to the specific error raised.`,
|
|
12763
|
+
messageText: `The \`catch\` callback in \`${nodeText}\` returns \`unknown\`, so the Effect error type stays untyped. A specific typed error preserves error-channel information, for example by narrowing the value or wrapping it in \`Data.TaggedError\`.`,
|
|
12711
12764
|
fixes: []
|
|
12712
12765
|
});
|
|
12713
12766
|
}
|
|
@@ -12804,7 +12857,7 @@ var unnecessaryFailYieldableError = createDiagnostic({
|
|
|
12804
12857
|
map5(
|
|
12805
12858
|
() => report({
|
|
12806
12859
|
location: node,
|
|
12807
|
-
messageText:
|
|
12860
|
+
messageText: "This `yield* Effect.fail(...)` passes a yieldable error value. `yield*` represents that value directly without wrapping it in `Effect.fail`.",
|
|
12808
12861
|
fixes: [{
|
|
12809
12862
|
fixName: "unnecessaryFailYieldableError_fix",
|
|
12810
12863
|
description: "Replace yield* Effect.fail with yield*",
|
|
@@ -12909,7 +12962,7 @@ var unnecessaryPipeChain = createDiagnostic({
|
|
|
12909
12962
|
map5(({ innerCall, pipeCall }) => {
|
|
12910
12963
|
report({
|
|
12911
12964
|
location: node,
|
|
12912
|
-
messageText: `
|
|
12965
|
+
messageText: "This expression contains chained `pipe` calls that can be simplified to a single `pipe` call.",
|
|
12913
12966
|
fixes: [{
|
|
12914
12967
|
fixName: "unnecessaryPipeChain_fix",
|
|
12915
12968
|
description: "Rewrite as single pipe call",
|