@effect/language-service 0.84.2 → 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 +127 -106
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +80 -59
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +80 -59
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +80 -59
- package/transform.js.map +1 -1
|
@@ -3481,6 +3481,14 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3481
3481
|
),
|
|
3482
3482
|
([A, E, R]) => ({ A, E, R })
|
|
3483
3483
|
);
|
|
3484
|
+
const streamVarianceStruct = (type, atLocation) => map4(
|
|
3485
|
+
all(
|
|
3486
|
+
varianceStructCovariantType(type, atLocation, "_A"),
|
|
3487
|
+
varianceStructCovariantType(type, atLocation, "_E"),
|
|
3488
|
+
varianceStructCovariantType(type, atLocation, "_R")
|
|
3489
|
+
),
|
|
3490
|
+
([A, E, R]) => ({ A, E, R })
|
|
3491
|
+
);
|
|
3484
3492
|
const layerVarianceStruct = (type, atLocation) => map4(
|
|
3485
3493
|
all(
|
|
3486
3494
|
varianceStructContravariantType(type, atLocation, "_ROut"),
|
|
@@ -3527,6 +3535,21 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3527
3535
|
"TypeParser.strictEffectType",
|
|
3528
3536
|
(type) => type
|
|
3529
3537
|
);
|
|
3538
|
+
const streamType = cachedBy(
|
|
3539
|
+
fn("TypeParser.streamType")(function* (type, atLocation) {
|
|
3540
|
+
if (supportedEffect() === "v3") {
|
|
3541
|
+
return yield* effectType(type, atLocation);
|
|
3542
|
+
}
|
|
3543
|
+
const typeIdSymbol = typeChecker.getPropertyOfType(type, "~effect/Stream");
|
|
3544
|
+
if (!typeIdSymbol) {
|
|
3545
|
+
return yield* typeParserIssue("Type is not a stream", type, atLocation);
|
|
3546
|
+
}
|
|
3547
|
+
const typeIdType = typeChecker.getTypeOfSymbolAtLocation(typeIdSymbol, atLocation);
|
|
3548
|
+
return yield* streamVarianceStruct(typeIdType, atLocation);
|
|
3549
|
+
}),
|
|
3550
|
+
"TypeParser.streamType",
|
|
3551
|
+
(type) => type
|
|
3552
|
+
);
|
|
3530
3553
|
const isEffectTypeSourceFile = cachedBy(
|
|
3531
3554
|
fn("TypeParser.isEffectTypeSourceFile")(function* (sourceFile) {
|
|
3532
3555
|
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
@@ -5262,6 +5285,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
5262
5285
|
isServiceMapTypeSourceFile,
|
|
5263
5286
|
isNodeReferenceToServiceMapModuleApi,
|
|
5264
5287
|
effectType,
|
|
5288
|
+
streamType,
|
|
5265
5289
|
strictEffectType,
|
|
5266
5290
|
layerType,
|
|
5267
5291
|
fiberType,
|
|
@@ -5489,7 +5513,7 @@ var catchAllToMapError = createDiagnostic({
|
|
|
5489
5513
|
const { failArg, failCall } = failCallInfo;
|
|
5490
5514
|
report({
|
|
5491
5515
|
location: transformation.callee,
|
|
5492
|
-
messageText:
|
|
5516
|
+
messageText: `\`Effect.mapError\` expresses the same error-type transformation more directly than \`Effect.${catchAllName}\` followed by \`Effect.fail\`.`,
|
|
5493
5517
|
fixes: [{
|
|
5494
5518
|
fixName: "catchAllToMapError_fix",
|
|
5495
5519
|
description: "Replace with Effect.mapError",
|
|
@@ -5553,7 +5577,7 @@ var catchUnfailableEffect = createDiagnostic({
|
|
|
5553
5577
|
if (E.flags & ts.TypeFlags.Never) {
|
|
5554
5578
|
report({
|
|
5555
5579
|
location: transformation.callee,
|
|
5556
|
-
messageText:
|
|
5580
|
+
messageText: "The previous Effect does not fail, so this error-handling branch will never run.",
|
|
5557
5581
|
fixes: []
|
|
5558
5582
|
});
|
|
5559
5583
|
}
|
|
@@ -5616,7 +5640,7 @@ var classSelfMismatch = createDiagnostic({
|
|
|
5616
5640
|
if (actualName !== expectedName) {
|
|
5617
5641
|
report({
|
|
5618
5642
|
location: selfTypeNode,
|
|
5619
|
-
messageText: `Self type parameter should be
|
|
5643
|
+
messageText: `The \`Self\` type parameter for this class should be \`${expectedName}\`.`,
|
|
5620
5644
|
fixes: [{
|
|
5621
5645
|
fixName: "classSelfMismatch_fix",
|
|
5622
5646
|
description: `Replace '${actualName}' with '${expectedName}'`,
|
|
@@ -5806,7 +5830,7 @@ var deterministicKeys = createDiagnostic({
|
|
|
5806
5830
|
if (actualIdentifier !== expectedKey) {
|
|
5807
5831
|
report({
|
|
5808
5832
|
location: keyStringLiteral,
|
|
5809
|
-
messageText: `
|
|
5833
|
+
messageText: `This key does not match the deterministic key for this declaration. The expected key is \`${expectedKey}\`.`,
|
|
5810
5834
|
fixes: [{
|
|
5811
5835
|
fixName: "deterministicKeys_fix",
|
|
5812
5836
|
description: `Replace '${actualIdentifier}' with '${expectedKey}'`,
|
|
@@ -5845,9 +5869,8 @@ var duplicatePackage = createDiagnostic({
|
|
|
5845
5869
|
const versions = Object.keys(resolvedPackages[packageName]);
|
|
5846
5870
|
report({
|
|
5847
5871
|
location: sourceFile.statements[0],
|
|
5848
|
-
messageText: `
|
|
5849
|
-
|
|
5850
|
-
If this is intended set the LSP config "allowedDuplicatedPackages" to ${JSON.stringify(options.allowedDuplicatedPackages.concat([packageName]))}.
|
|
5872
|
+
messageText: `Multiple versions of package \`${packageName}\` were detected: ${versions.join(", ")}. Package duplication can change runtime identity and type equality across Effect modules.
|
|
5873
|
+
If this is intentional, set the LSP config \`allowedDuplicatedPackages\` to ${JSON.stringify(options.allowedDuplicatedPackages.concat([packageName]))}.
|
|
5851
5874
|
|
|
5852
5875
|
${versions.map((version) => `- found ${version} at ${resolvedPackages[packageName][version]}`).join("\n")}`,
|
|
5853
5876
|
fixes: []
|
|
@@ -5955,7 +5978,7 @@ var effectFnIife = createDiagnostic({
|
|
|
5955
5978
|
const traceExpressionText = traceExpression ? sourceFile.text.slice(traceExpression.pos, traceExpression.end) : void 0;
|
|
5956
5979
|
report({
|
|
5957
5980
|
location: node,
|
|
5958
|
-
messageText:
|
|
5981
|
+
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` : ``}.`,
|
|
5959
5982
|
fixes
|
|
5960
5983
|
});
|
|
5961
5984
|
}
|
|
@@ -6040,7 +6063,7 @@ var effectFnImplicitAny = createDiagnostic({
|
|
|
6040
6063
|
const parameterName = getParameterName(ts, parameter.name);
|
|
6041
6064
|
report({
|
|
6042
6065
|
location: parameter.name,
|
|
6043
|
-
messageText: `Parameter
|
|
6066
|
+
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.`,
|
|
6044
6067
|
fixes: []
|
|
6045
6068
|
});
|
|
6046
6069
|
}
|
|
@@ -6636,7 +6659,7 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
6636
6659
|
const expectedSignature = generateExpectedSignature();
|
|
6637
6660
|
report({
|
|
6638
6661
|
location: nameIdentifier ?? targetNode,
|
|
6639
|
-
messageText: `
|
|
6662
|
+
messageText: `This expression can be rewritten in the reusable function form \`${expectedSignature}\`.`,
|
|
6640
6663
|
fixes
|
|
6641
6664
|
});
|
|
6642
6665
|
}
|
|
@@ -6848,7 +6871,7 @@ var effectMapVoid = createDiagnostic({
|
|
|
6848
6871
|
if (isNone2(match2)) continue;
|
|
6849
6872
|
report({
|
|
6850
6873
|
location: node.expression,
|
|
6851
|
-
messageText: "
|
|
6874
|
+
messageText: "This expression discards the success value through mapping. `Effect.asVoid` represents that form directly.",
|
|
6852
6875
|
fixes: [{
|
|
6853
6876
|
fixName: "effectMapVoid_fix",
|
|
6854
6877
|
description: "Replace with Effect.asVoid",
|
|
@@ -6903,7 +6926,7 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
6903
6926
|
if (!tsUtils.isVoidExpression(argument)) continue;
|
|
6904
6927
|
report({
|
|
6905
6928
|
location: node,
|
|
6906
|
-
messageText: "Effect.void
|
|
6929
|
+
messageText: "`Effect.void` represents the same outcome as `Effect.succeed(undefined)` or `Effect.succeed(void 0)`.",
|
|
6907
6930
|
fixes: [{
|
|
6908
6931
|
fixName: "effectSucceedWithVoid_fix",
|
|
6909
6932
|
description: "Replace with Effect.void",
|
|
@@ -6965,7 +6988,7 @@ var extendsNativeError = createDiagnostic({
|
|
|
6965
6988
|
if (isNativeError) {
|
|
6966
6989
|
report({
|
|
6967
6990
|
location: node.name ?? typeExpression,
|
|
6968
|
-
messageText: "
|
|
6991
|
+
messageText: "This class extends the native `Error` type directly. Untagged native errors lose distinction in the Effect failure channel.",
|
|
6969
6992
|
fixes: []
|
|
6970
6993
|
});
|
|
6971
6994
|
}
|
|
@@ -7010,7 +7033,12 @@ var floatingEffect = createDiagnostic({
|
|
|
7010
7033
|
if (!isFloatingExpression(node)) continue;
|
|
7011
7034
|
const type = typeCheckerUtils.getTypeAtLocation(node.expression);
|
|
7012
7035
|
if (!type) continue;
|
|
7013
|
-
const effect = yield* option(
|
|
7036
|
+
const effect = yield* option(
|
|
7037
|
+
pipe(
|
|
7038
|
+
typeParser.effectType(type, node.expression),
|
|
7039
|
+
orElse2(() => typeParser.streamType(type, node.expression))
|
|
7040
|
+
)
|
|
7041
|
+
);
|
|
7014
7042
|
if (isSome2(effect)) {
|
|
7015
7043
|
const allowedFloatingEffects = yield* pipe(
|
|
7016
7044
|
typeParser.fiberType(type, node.expression),
|
|
@@ -7019,10 +7047,9 @@ var floatingEffect = createDiagnostic({
|
|
|
7019
7047
|
);
|
|
7020
7048
|
if (isNone2(allowedFloatingEffects)) {
|
|
7021
7049
|
const isStrictEffect = yield* option(typeParser.strictEffectType(type, node.expression));
|
|
7022
|
-
const name = isSome2(isStrictEffect) ? "Effect" : "Effect-able " + typeChecker.typeToString(type);
|
|
7023
7050
|
report({
|
|
7024
7051
|
location: node,
|
|
7025
|
-
messageText:
|
|
7052
|
+
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.`,
|
|
7026
7053
|
fixes: []
|
|
7027
7054
|
});
|
|
7028
7055
|
}
|
|
@@ -7117,7 +7144,7 @@ var makeGlobalConsoleApply = (checkInEffect) => fn(`globalConsole${checkInEffect
|
|
|
7117
7144
|
if (inEffect !== checkInEffect) continue;
|
|
7118
7145
|
report({
|
|
7119
7146
|
location: node,
|
|
7120
|
-
messageText: checkInEffect ? `
|
|
7147
|
+
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}\`.`,
|
|
7121
7148
|
fixes: []
|
|
7122
7149
|
});
|
|
7123
7150
|
}
|
|
@@ -7166,10 +7193,10 @@ var makeGlobalDateApply = (checkInEffect) => fn(`globalDate${checkInEffect ? "In
|
|
|
7166
7193
|
let objectNode;
|
|
7167
7194
|
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.idText(node.expression.name) === "now") {
|
|
7168
7195
|
objectNode = node.expression.expression;
|
|
7169
|
-
messageText = checkInEffect ? "
|
|
7196
|
+
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.";
|
|
7170
7197
|
} else if (ts.isNewExpression(node)) {
|
|
7171
7198
|
objectNode = node.expression;
|
|
7172
|
-
messageText = checkInEffect ? "
|
|
7199
|
+
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.";
|
|
7173
7200
|
}
|
|
7174
7201
|
if (!messageText || !objectNode) continue;
|
|
7175
7202
|
const symbol3 = typeChecker.getSymbolAtLocation(objectNode);
|
|
@@ -7252,7 +7279,7 @@ var globalErrorInEffectCatch = createDiagnostic({
|
|
|
7252
7279
|
);
|
|
7253
7280
|
report({
|
|
7254
7281
|
location: node.expression,
|
|
7255
|
-
messageText: `The
|
|
7282
|
+
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.`,
|
|
7256
7283
|
fixes: []
|
|
7257
7284
|
});
|
|
7258
7285
|
}
|
|
@@ -7332,7 +7359,7 @@ var makeGlobalFetchApply = (checkInEffect) => fn(`globalFetch${checkInEffect ? "
|
|
|
7332
7359
|
if (!fetchSymbol) return;
|
|
7333
7360
|
const effectVersion = typeParser.supportedEffect();
|
|
7334
7361
|
const packageName = effectVersion === "v3" ? "@effect/platform" : "effect/unstable/http";
|
|
7335
|
-
const messageText = checkInEffect ? `
|
|
7362
|
+
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}\`.`;
|
|
7336
7363
|
const nodeToVisit = [];
|
|
7337
7364
|
const appendNodeToVisit = (node) => {
|
|
7338
7365
|
nodeToVisit.push(node);
|
|
@@ -7405,7 +7432,7 @@ var makeGlobalRandomApply = (checkInEffect) => fn(`globalRandom${checkInEffect ?
|
|
|
7405
7432
|
if (inEffect !== checkInEffect) continue;
|
|
7406
7433
|
report({
|
|
7407
7434
|
location: node,
|
|
7408
|
-
messageText: checkInEffect ? "
|
|
7435
|
+
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.",
|
|
7409
7436
|
fixes: []
|
|
7410
7437
|
});
|
|
7411
7438
|
}
|
|
@@ -7436,12 +7463,12 @@ var globalRandom = createDiagnostic({
|
|
|
7436
7463
|
// src/diagnostics/globalTimersInEffect.ts
|
|
7437
7464
|
var timerAlternatives = {
|
|
7438
7465
|
"setTimeout": {
|
|
7439
|
-
inEffect: "
|
|
7440
|
-
outsideEffect: "
|
|
7466
|
+
inEffect: "This Effect code uses `setTimeout`, the corresponding timer API in this context is `Effect.sleep or Schedule` from Effect.",
|
|
7467
|
+
outsideEffect: "This code uses `setTimeout`, the corresponding Effect timer API is `Effect.sleep or Schedule` from Effect."
|
|
7441
7468
|
},
|
|
7442
7469
|
"setInterval": {
|
|
7443
|
-
inEffect: "
|
|
7444
|
-
outsideEffect: "
|
|
7470
|
+
inEffect: "This Effect code uses `setInterval`, the corresponding timer API in this context is `Schedule or Effect.repeat` from Effect.",
|
|
7471
|
+
outsideEffect: "This code uses `setInterval`, the corresponding Effect timer API is `Schedule or Effect.repeat` from Effect."
|
|
7445
7472
|
}
|
|
7446
7473
|
};
|
|
7447
7474
|
var makeGlobalTimersApply = (checkInEffect) => fn(`globalTimers${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
@@ -7683,7 +7710,7 @@ var instanceOfSchema = createDiagnostic({
|
|
|
7683
7710
|
if (isSchemaType._tag === "Some") {
|
|
7684
7711
|
report({
|
|
7685
7712
|
location: node,
|
|
7686
|
-
messageText: "
|
|
7713
|
+
messageText: "This code uses `instanceof` with an Effect Schema type. `Schema.is` is the schema-aware runtime check for this case.",
|
|
7687
7714
|
fixes: [{
|
|
7688
7715
|
fixName: "instanceOfSchema_fix",
|
|
7689
7716
|
description: "Replace with Schema.is",
|
|
@@ -7953,7 +7980,7 @@ var leakingRequirements = createDiagnostic({
|
|
|
7953
7980
|
location: node,
|
|
7954
7981
|
messageText: `Methods of this Service require \`${requirementsStr}\` from every caller.
|
|
7955
7982
|
|
|
7956
|
-
|
|
7983
|
+
The requirement becomes part of the public service surface instead of remaining internal to Layer implementation.
|
|
7957
7984
|
|
|
7958
7985
|
Resolve these dependencies at Layer creation and provide them to each method, so the service's type reflects its purpose, not its implementation.
|
|
7959
7986
|
|
|
@@ -8150,7 +8177,7 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
8150
8177
|
).trim() : "";
|
|
8151
8178
|
report({
|
|
8152
8179
|
location: flow2.node,
|
|
8153
|
-
messageText: `
|
|
8180
|
+
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.`,
|
|
8154
8181
|
fixes: [{
|
|
8155
8182
|
fixName: "missedPipeableOpportunity_fix",
|
|
8156
8183
|
description: "Convert to pipe style",
|
|
@@ -8231,7 +8258,7 @@ var missingEffectContext = createDiagnostic({
|
|
|
8231
8258
|
(missingTypes) => missingTypes.length > 0 ? report(
|
|
8232
8259
|
{
|
|
8233
8260
|
location: node,
|
|
8234
|
-
messageText: `
|
|
8261
|
+
messageText: `This Effect requires a service that is missing from the expected Effect context: \`${sortTypes(missingTypes).map((_) => typeChecker.typeToString(_)).join(" | ")}\`.`,
|
|
8235
8262
|
fixes: []
|
|
8236
8263
|
}
|
|
8237
8264
|
) : void 0
|
|
@@ -8582,7 +8609,7 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
8582
8609
|
}];
|
|
8583
8610
|
report({
|
|
8584
8611
|
location: unwrapped,
|
|
8585
|
-
messageText:
|
|
8612
|
+
messageText: "This Effect never succeeds; using `return yield*` preserves a definitive generator exit point for type narrowing and tooling support.",
|
|
8586
8613
|
fixes: fix
|
|
8587
8614
|
});
|
|
8588
8615
|
}
|
|
@@ -8638,7 +8665,7 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
8638
8665
|
brokenGenerators.forEach(
|
|
8639
8666
|
(pos) => report({
|
|
8640
8667
|
location: { pos, end: pos + "function".length },
|
|
8641
|
-
messageText: `
|
|
8668
|
+
messageText: "This uses `yield` for an `Effect` value. `yield*` is the Effect-aware form in this context.",
|
|
8642
8669
|
fixes: []
|
|
8643
8670
|
})
|
|
8644
8671
|
);
|
|
@@ -8660,7 +8687,7 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
8660
8687
|
}] : [];
|
|
8661
8688
|
report({
|
|
8662
8689
|
location: node,
|
|
8663
|
-
messageText: `
|
|
8690
|
+
messageText: "This uses `yield` for an `Effect` value. `yield*` is the Effect-aware form in this context.",
|
|
8664
8691
|
fixes: fix
|
|
8665
8692
|
});
|
|
8666
8693
|
});
|
|
@@ -8728,7 +8755,7 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
8728
8755
|
if (chunk.length < 2) continue;
|
|
8729
8756
|
report({
|
|
8730
8757
|
location: chunk[0].node,
|
|
8731
|
-
messageText: "
|
|
8758
|
+
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.",
|
|
8732
8759
|
fixes: [{
|
|
8733
8760
|
fixName: "multipleEffectProvide_fix",
|
|
8734
8761
|
description: "Combine into a single provide",
|
|
@@ -8818,7 +8845,7 @@ var nodeBuiltinImport = createDiagnostic({
|
|
|
8818
8845
|
if (match2) {
|
|
8819
8846
|
report({
|
|
8820
8847
|
location: statement.moduleSpecifier,
|
|
8821
|
-
messageText: `
|
|
8848
|
+
messageText: `This module reference uses the \`${match2.module}\` module, the corresponding Effect API is \`${match2.alternative}\` from \`${match2.package}\`.`,
|
|
8822
8849
|
fixes: []
|
|
8823
8850
|
});
|
|
8824
8851
|
}
|
|
@@ -8831,7 +8858,7 @@ var nodeBuiltinImport = createDiagnostic({
|
|
|
8831
8858
|
if (match2) {
|
|
8832
8859
|
report({
|
|
8833
8860
|
location: arg,
|
|
8834
|
-
messageText: `
|
|
8861
|
+
messageText: `This module reference uses the \`${match2.module}\` module, the corresponding Effect API is \`${match2.alternative}\` from \`${match2.package}\`.`,
|
|
8835
8862
|
fixes: []
|
|
8836
8863
|
});
|
|
8837
8864
|
}
|
|
@@ -8885,7 +8912,7 @@ var nonObjectEffectServiceType = createDiagnostic({
|
|
|
8885
8912
|
const propertyValue = property.initializer;
|
|
8886
8913
|
const errorToReport = {
|
|
8887
8914
|
location: property.name,
|
|
8888
|
-
messageText: "Effect.Service
|
|
8915
|
+
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.",
|
|
8889
8916
|
fixes: []
|
|
8890
8917
|
};
|
|
8891
8918
|
if (propertyName === "succeed") {
|
|
@@ -9647,7 +9674,7 @@ var outdatedApi = createDiagnostic({
|
|
|
9647
9674
|
hasReported = true;
|
|
9648
9675
|
report({
|
|
9649
9676
|
location: propertyAccess.name,
|
|
9650
|
-
messageText:
|
|
9677
|
+
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.`,
|
|
9651
9678
|
fixes: []
|
|
9652
9679
|
});
|
|
9653
9680
|
}
|
|
@@ -9690,7 +9717,7 @@ var outdatedApi = createDiagnostic({
|
|
|
9690
9717
|
if (hasReported) {
|
|
9691
9718
|
report({
|
|
9692
9719
|
location: { pos: 0, end: 0 },
|
|
9693
|
-
messageText: "This project targets Effect v4, but
|
|
9720
|
+
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.",
|
|
9694
9721
|
fixes: []
|
|
9695
9722
|
});
|
|
9696
9723
|
}
|
|
@@ -10935,7 +10962,7 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
10935
10962
|
};
|
|
10936
10963
|
report({
|
|
10937
10964
|
location: member,
|
|
10938
|
-
messageText: "
|
|
10965
|
+
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.",
|
|
10939
10966
|
fixes: (member.body ? [fixAsStaticNew] : []).concat([{
|
|
10940
10967
|
fixName: "overriddenSchemaConstructor_fix",
|
|
10941
10968
|
description: "Remove the constructor override",
|
|
@@ -11057,7 +11084,7 @@ var preferSchemaOverJson = createDiagnostic({
|
|
|
11057
11084
|
if (isSome2(match2)) {
|
|
11058
11085
|
report({
|
|
11059
11086
|
location: match2.value,
|
|
11060
|
-
messageText: "
|
|
11087
|
+
messageText: "This code uses `JSON.parse` or `JSON.stringify`. Effect Schema provides Effect-aware APIs for JSON parsing and stringifying.",
|
|
11061
11088
|
fixes: []
|
|
11062
11089
|
});
|
|
11063
11090
|
}
|
|
@@ -11175,9 +11202,7 @@ var returnEffectInGen = createDiagnostic({
|
|
|
11175
11202
|
}] : [];
|
|
11176
11203
|
report({
|
|
11177
11204
|
location: node,
|
|
11178
|
-
messageText:
|
|
11179
|
-
Maybe you wanted to return yield* instead?
|
|
11180
|
-
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.`,
|
|
11205
|
+
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.",
|
|
11181
11206
|
fixes: fix
|
|
11182
11207
|
});
|
|
11183
11208
|
}),
|
|
@@ -11332,9 +11357,7 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
11332
11357
|
);
|
|
11333
11358
|
});
|
|
11334
11359
|
const v4MethodName = `${isEffectRunCall.value.methodName}With`;
|
|
11335
|
-
const messageText = supportedEffect === "v4" ?
|
|
11336
|
-
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.
|
|
11337
|
-
Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`;
|
|
11360
|
+
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}\`.`;
|
|
11338
11361
|
report({
|
|
11339
11362
|
location: node.expression,
|
|
11340
11363
|
messageText,
|
|
@@ -11347,7 +11370,7 @@ Consider extracting the Runtime by using for example Effect.runtime and then use
|
|
|
11347
11370
|
} else {
|
|
11348
11371
|
report({
|
|
11349
11372
|
location: node.expression,
|
|
11350
|
-
messageText:
|
|
11373
|
+
messageText: `\`${nodeText}\` is called inside an existing Effect context. Here, the inner Effect can be used directly.`,
|
|
11351
11374
|
fixes: []
|
|
11352
11375
|
});
|
|
11353
11376
|
}
|
|
@@ -11402,7 +11425,7 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
11402
11425
|
const otherProperties = arg.properties.filter((prop) => prop !== tagProperty);
|
|
11403
11426
|
report({
|
|
11404
11427
|
location: node,
|
|
11405
|
-
messageText: "Schema.Struct
|
|
11428
|
+
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.",
|
|
11406
11429
|
fixes: [{
|
|
11407
11430
|
fixName: "schemaStructWithTag_fix",
|
|
11408
11431
|
description: "Replace with Schema.TaggedStruct",
|
|
@@ -11495,7 +11518,7 @@ var schemaSyncInEffect = createDiagnostic({
|
|
|
11495
11518
|
const effectMethodName = syncToEffectMethod[isSchemaSyncCall.value.methodName];
|
|
11496
11519
|
report({
|
|
11497
11520
|
location: node.expression,
|
|
11498
|
-
messageText:
|
|
11521
|
+
messageText: `\`${nodeText}\` is used inside an Effect generator. \`Schema.${effectMethodName}\` preserves the typed Effect error channel for this operation without throwing.`,
|
|
11499
11522
|
fixes: []
|
|
11500
11523
|
});
|
|
11501
11524
|
}
|
|
@@ -11555,7 +11578,7 @@ var schemaUnionOfLiterals = createDiagnostic({
|
|
|
11555
11578
|
const schemaLiteralExpression = firstLiteralCall.expression;
|
|
11556
11579
|
report({
|
|
11557
11580
|
location: node,
|
|
11558
|
-
messageText: "
|
|
11581
|
+
messageText: "This `Schema.Union` contains multiple `Schema.Literal` members and can be simplified to a single `Schema.Literal` call.",
|
|
11559
11582
|
fixes: [{
|
|
11560
11583
|
fixName: "schemaUnionOfLiterals_fix",
|
|
11561
11584
|
description: "Replace with a single Schema.Literal call",
|
|
@@ -11618,8 +11641,7 @@ var scopeInLayerEffect = createDiagnostic({
|
|
|
11618
11641
|
map4(
|
|
11619
11642
|
() => report({
|
|
11620
11643
|
location: node,
|
|
11621
|
-
messageText: `
|
|
11622
|
-
Consider using "scoped" instead to get rid of the scope in the requirements.`,
|
|
11644
|
+
messageText: "This layer construction leaves `Scope` in the requirement set. The scoped API removes `Scope` from the resulting requirements.",
|
|
11623
11645
|
fixes: methodIdentifier ? [{
|
|
11624
11646
|
fixName: "scopeInLayerEffect_scoped",
|
|
11625
11647
|
description: "Use scoped for Layer creation",
|
|
@@ -11719,7 +11741,7 @@ var serviceNotAsClass = createDiagnostic({
|
|
|
11719
11741
|
const shapeText = typeArgs.length > 0 ? typeArgs.map((t) => sourceFile.text.substring(ts.getTokenPosOfNode(t, sourceFile), t.end)).join(", ") : "Shape";
|
|
11720
11742
|
report({
|
|
11721
11743
|
location: callExpr,
|
|
11722
|
-
messageText:
|
|
11744
|
+
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, "")}") {}\`.`,
|
|
11723
11745
|
fixes: [{
|
|
11724
11746
|
fixName: "serviceNotAsClass",
|
|
11725
11747
|
description: `Convert to class declaration`,
|
|
@@ -11932,7 +11954,7 @@ var tryCatchInEffectGen = createDiagnostic({
|
|
|
11932
11954
|
map4(() => {
|
|
11933
11955
|
report({
|
|
11934
11956
|
location: node,
|
|
11935
|
-
messageText: `
|
|
11957
|
+
messageText: `This Effect generator contains \`try/catch\`; in this context, error handling is expressed with Effect APIs such as ${alternatives.join(", ")}).`,
|
|
11936
11958
|
fixes: []
|
|
11937
11959
|
});
|
|
11938
11960
|
}),
|
|
@@ -11993,8 +12015,7 @@ var unknownInEffectCatch = createDiagnostic({
|
|
|
11993
12015
|
);
|
|
11994
12016
|
report({
|
|
11995
12017
|
location: node.expression,
|
|
11996
|
-
messageText: `The
|
|
11997
|
-
Consider wrapping unknown errors into Effect's Data.TaggedError for example, or narrow down the type to the specific error raised.`,
|
|
12018
|
+
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\`.`,
|
|
11998
12019
|
fixes: []
|
|
11999
12020
|
});
|
|
12000
12021
|
}
|
|
@@ -12091,7 +12112,7 @@ var unnecessaryFailYieldableError = createDiagnostic({
|
|
|
12091
12112
|
map4(
|
|
12092
12113
|
() => report({
|
|
12093
12114
|
location: node,
|
|
12094
|
-
messageText:
|
|
12115
|
+
messageText: "This `yield* Effect.fail(...)` passes a yieldable error value. `yield*` represents that value directly without wrapping it in `Effect.fail`.",
|
|
12095
12116
|
fixes: [{
|
|
12096
12117
|
fixName: "unnecessaryFailYieldableError_fix",
|
|
12097
12118
|
description: "Replace yield* Effect.fail with yield*",
|
|
@@ -12196,7 +12217,7 @@ var unnecessaryPipeChain = createDiagnostic({
|
|
|
12196
12217
|
map4(({ innerCall, pipeCall }) => {
|
|
12197
12218
|
report({
|
|
12198
12219
|
location: node,
|
|
12199
|
-
messageText: `
|
|
12220
|
+
messageText: "This expression contains chained `pipe` calls that can be simplified to a single `pipe` call.",
|
|
12200
12221
|
fixes: [{
|
|
12201
12222
|
fixName: "unnecessaryPipeChain_fix",
|
|
12202
12223
|
description: "Rewrite as single pipe call",
|