@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
|
@@ -3122,10 +3122,42 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
3122
3122
|
if (node.parent && ts.isJsxOpeningElement(node.parent) && node.parent.tagName === node) return;
|
|
3123
3123
|
if (node.parent && ts.isJsxClosingElement(node.parent) && node.parent.tagName === node) return;
|
|
3124
3124
|
if (node.parent && ts.isJsxAttribute(node.parent) && node.parent.name === node) return;
|
|
3125
|
+
if (isInsideTypeOnlyHeritageExpression(node)) return;
|
|
3125
3126
|
if (ts.isExpression(node) || ts.isTypeNode(node)) {
|
|
3126
3127
|
return typeChecker.getTypeAtLocation(node);
|
|
3127
3128
|
}
|
|
3128
3129
|
}
|
|
3130
|
+
function isInsideTypeOnlyHeritageExpression(node) {
|
|
3131
|
+
if (ts.isExpressionWithTypeArguments(node)) {
|
|
3132
|
+
return isTypeOnlyHeritageClause(node.parent);
|
|
3133
|
+
}
|
|
3134
|
+
if (!ts.isIdentifier(node) && !ts.isPropertyAccessExpression(node)) {
|
|
3135
|
+
return false;
|
|
3136
|
+
}
|
|
3137
|
+
for (let current = node.parent; current; current = current.parent) {
|
|
3138
|
+
if (ts.isPropertyAccessExpression(current)) {
|
|
3139
|
+
continue;
|
|
3140
|
+
}
|
|
3141
|
+
if (ts.isExpressionWithTypeArguments(current)) {
|
|
3142
|
+
return isTypeOnlyHeritageClause(current.parent);
|
|
3143
|
+
}
|
|
3144
|
+
return false;
|
|
3145
|
+
}
|
|
3146
|
+
return false;
|
|
3147
|
+
}
|
|
3148
|
+
function isTypeOnlyHeritageClause(node) {
|
|
3149
|
+
if (!node || !ts.isHeritageClause(node)) {
|
|
3150
|
+
return false;
|
|
3151
|
+
}
|
|
3152
|
+
const container = node.parent;
|
|
3153
|
+
if (!container) {
|
|
3154
|
+
return false;
|
|
3155
|
+
}
|
|
3156
|
+
if (ts.isInterfaceDeclaration(container)) {
|
|
3157
|
+
return true;
|
|
3158
|
+
}
|
|
3159
|
+
return ts.isClassLike(container) && node.token === ts.SyntaxKind.ImplementsKeyword;
|
|
3160
|
+
}
|
|
3129
3161
|
function resolveToGlobalSymbol(symbol3) {
|
|
3130
3162
|
if (symbol3.flags & ts.SymbolFlags.Alias) {
|
|
3131
3163
|
symbol3 = typeChecker.getAliasedSymbol(symbol3);
|
|
@@ -3449,6 +3481,14 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3449
3481
|
),
|
|
3450
3482
|
([A, E, R]) => ({ A, E, R })
|
|
3451
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
|
+
);
|
|
3452
3492
|
const layerVarianceStruct = (type, atLocation) => map4(
|
|
3453
3493
|
all(
|
|
3454
3494
|
varianceStructContravariantType(type, atLocation, "_ROut"),
|
|
@@ -3495,6 +3535,21 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3495
3535
|
"TypeParser.strictEffectType",
|
|
3496
3536
|
(type) => type
|
|
3497
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
|
+
);
|
|
3498
3553
|
const isEffectTypeSourceFile = cachedBy(
|
|
3499
3554
|
fn("TypeParser.isEffectTypeSourceFile")(function* (sourceFile) {
|
|
3500
3555
|
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
@@ -5230,6 +5285,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
5230
5285
|
isServiceMapTypeSourceFile,
|
|
5231
5286
|
isNodeReferenceToServiceMapModuleApi,
|
|
5232
5287
|
effectType,
|
|
5288
|
+
streamType,
|
|
5233
5289
|
strictEffectType,
|
|
5234
5290
|
layerType,
|
|
5235
5291
|
fiberType,
|
|
@@ -5457,7 +5513,7 @@ var catchAllToMapError = createDiagnostic({
|
|
|
5457
5513
|
const { failArg, failCall } = failCallInfo;
|
|
5458
5514
|
report({
|
|
5459
5515
|
location: transformation.callee,
|
|
5460
|
-
messageText:
|
|
5516
|
+
messageText: `\`Effect.mapError\` expresses the same error-type transformation more directly than \`Effect.${catchAllName}\` followed by \`Effect.fail\`.`,
|
|
5461
5517
|
fixes: [{
|
|
5462
5518
|
fixName: "catchAllToMapError_fix",
|
|
5463
5519
|
description: "Replace with Effect.mapError",
|
|
@@ -5521,7 +5577,7 @@ var catchUnfailableEffect = createDiagnostic({
|
|
|
5521
5577
|
if (E.flags & ts.TypeFlags.Never) {
|
|
5522
5578
|
report({
|
|
5523
5579
|
location: transformation.callee,
|
|
5524
|
-
messageText:
|
|
5580
|
+
messageText: "The previous Effect does not fail, so this error-handling branch will never run.",
|
|
5525
5581
|
fixes: []
|
|
5526
5582
|
});
|
|
5527
5583
|
}
|
|
@@ -5584,7 +5640,7 @@ var classSelfMismatch = createDiagnostic({
|
|
|
5584
5640
|
if (actualName !== expectedName) {
|
|
5585
5641
|
report({
|
|
5586
5642
|
location: selfTypeNode,
|
|
5587
|
-
messageText: `Self type parameter should be
|
|
5643
|
+
messageText: `The \`Self\` type parameter for this class should be \`${expectedName}\`.`,
|
|
5588
5644
|
fixes: [{
|
|
5589
5645
|
fixName: "classSelfMismatch_fix",
|
|
5590
5646
|
description: `Replace '${actualName}' with '${expectedName}'`,
|
|
@@ -5774,7 +5830,7 @@ var deterministicKeys = createDiagnostic({
|
|
|
5774
5830
|
if (actualIdentifier !== expectedKey) {
|
|
5775
5831
|
report({
|
|
5776
5832
|
location: keyStringLiteral,
|
|
5777
|
-
messageText: `
|
|
5833
|
+
messageText: `This key does not match the deterministic key for this declaration. The expected key is \`${expectedKey}\`.`,
|
|
5778
5834
|
fixes: [{
|
|
5779
5835
|
fixName: "deterministicKeys_fix",
|
|
5780
5836
|
description: `Replace '${actualIdentifier}' with '${expectedKey}'`,
|
|
@@ -5813,9 +5869,8 @@ var duplicatePackage = createDiagnostic({
|
|
|
5813
5869
|
const versions = Object.keys(resolvedPackages[packageName]);
|
|
5814
5870
|
report({
|
|
5815
5871
|
location: sourceFile.statements[0],
|
|
5816
|
-
messageText: `
|
|
5817
|
-
|
|
5818
|
-
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]))}.
|
|
5819
5874
|
|
|
5820
5875
|
${versions.map((version) => `- found ${version} at ${resolvedPackages[packageName][version]}`).join("\n")}`,
|
|
5821
5876
|
fixes: []
|
|
@@ -5923,7 +5978,7 @@ var effectFnIife = createDiagnostic({
|
|
|
5923
5978
|
const traceExpressionText = traceExpression ? sourceFile.text.slice(traceExpression.pos, traceExpression.end) : void 0;
|
|
5924
5979
|
report({
|
|
5925
5980
|
location: node,
|
|
5926
|
-
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` : ``}.`,
|
|
5927
5982
|
fixes
|
|
5928
5983
|
});
|
|
5929
5984
|
}
|
|
@@ -6008,7 +6063,7 @@ var effectFnImplicitAny = createDiagnostic({
|
|
|
6008
6063
|
const parameterName = getParameterName(ts, parameter.name);
|
|
6009
6064
|
report({
|
|
6010
6065
|
location: parameter.name,
|
|
6011
|
-
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.`,
|
|
6012
6067
|
fixes: []
|
|
6013
6068
|
});
|
|
6014
6069
|
}
|
|
@@ -6604,7 +6659,7 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
6604
6659
|
const expectedSignature = generateExpectedSignature();
|
|
6605
6660
|
report({
|
|
6606
6661
|
location: nameIdentifier ?? targetNode,
|
|
6607
|
-
messageText: `
|
|
6662
|
+
messageText: `This expression can be rewritten in the reusable function form \`${expectedSignature}\`.`,
|
|
6608
6663
|
fixes
|
|
6609
6664
|
});
|
|
6610
6665
|
}
|
|
@@ -6816,7 +6871,7 @@ var effectMapVoid = createDiagnostic({
|
|
|
6816
6871
|
if (isNone2(match2)) continue;
|
|
6817
6872
|
report({
|
|
6818
6873
|
location: node.expression,
|
|
6819
|
-
messageText: "
|
|
6874
|
+
messageText: "This expression discards the success value through mapping. `Effect.asVoid` represents that form directly.",
|
|
6820
6875
|
fixes: [{
|
|
6821
6876
|
fixName: "effectMapVoid_fix",
|
|
6822
6877
|
description: "Replace with Effect.asVoid",
|
|
@@ -6871,7 +6926,7 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
6871
6926
|
if (!tsUtils.isVoidExpression(argument)) continue;
|
|
6872
6927
|
report({
|
|
6873
6928
|
location: node,
|
|
6874
|
-
messageText: "Effect.void
|
|
6929
|
+
messageText: "`Effect.void` represents the same outcome as `Effect.succeed(undefined)` or `Effect.succeed(void 0)`.",
|
|
6875
6930
|
fixes: [{
|
|
6876
6931
|
fixName: "effectSucceedWithVoid_fix",
|
|
6877
6932
|
description: "Replace with Effect.void",
|
|
@@ -6933,7 +6988,7 @@ var extendsNativeError = createDiagnostic({
|
|
|
6933
6988
|
if (isNativeError) {
|
|
6934
6989
|
report({
|
|
6935
6990
|
location: node.name ?? typeExpression,
|
|
6936
|
-
messageText: "
|
|
6991
|
+
messageText: "This class extends the native `Error` type directly. Untagged native errors lose distinction in the Effect failure channel.",
|
|
6937
6992
|
fixes: []
|
|
6938
6993
|
});
|
|
6939
6994
|
}
|
|
@@ -6978,7 +7033,12 @@ var floatingEffect = createDiagnostic({
|
|
|
6978
7033
|
if (!isFloatingExpression(node)) continue;
|
|
6979
7034
|
const type = typeCheckerUtils.getTypeAtLocation(node.expression);
|
|
6980
7035
|
if (!type) continue;
|
|
6981
|
-
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
|
+
);
|
|
6982
7042
|
if (isSome2(effect)) {
|
|
6983
7043
|
const allowedFloatingEffects = yield* pipe(
|
|
6984
7044
|
typeParser.fiberType(type, node.expression),
|
|
@@ -6987,10 +7047,9 @@ var floatingEffect = createDiagnostic({
|
|
|
6987
7047
|
);
|
|
6988
7048
|
if (isNone2(allowedFloatingEffects)) {
|
|
6989
7049
|
const isStrictEffect = yield* option(typeParser.strictEffectType(type, node.expression));
|
|
6990
|
-
const name = isSome2(isStrictEffect) ? "Effect" : "Effect-able " + typeChecker.typeToString(type);
|
|
6991
7050
|
report({
|
|
6992
7051
|
location: node,
|
|
6993
|
-
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.`,
|
|
6994
7053
|
fixes: []
|
|
6995
7054
|
});
|
|
6996
7055
|
}
|
|
@@ -7085,7 +7144,7 @@ var makeGlobalConsoleApply = (checkInEffect) => fn(`globalConsole${checkInEffect
|
|
|
7085
7144
|
if (inEffect !== checkInEffect) continue;
|
|
7086
7145
|
report({
|
|
7087
7146
|
location: node,
|
|
7088
|
-
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}\`.`,
|
|
7089
7148
|
fixes: []
|
|
7090
7149
|
});
|
|
7091
7150
|
}
|
|
@@ -7134,10 +7193,10 @@ var makeGlobalDateApply = (checkInEffect) => fn(`globalDate${checkInEffect ? "In
|
|
|
7134
7193
|
let objectNode;
|
|
7135
7194
|
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.idText(node.expression.name) === "now") {
|
|
7136
7195
|
objectNode = node.expression.expression;
|
|
7137
|
-
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.";
|
|
7138
7197
|
} else if (ts.isNewExpression(node)) {
|
|
7139
7198
|
objectNode = node.expression;
|
|
7140
|
-
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.";
|
|
7141
7200
|
}
|
|
7142
7201
|
if (!messageText || !objectNode) continue;
|
|
7143
7202
|
const symbol3 = typeChecker.getSymbolAtLocation(objectNode);
|
|
@@ -7220,7 +7279,7 @@ var globalErrorInEffectCatch = createDiagnostic({
|
|
|
7220
7279
|
);
|
|
7221
7280
|
report({
|
|
7222
7281
|
location: node.expression,
|
|
7223
|
-
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.`,
|
|
7224
7283
|
fixes: []
|
|
7225
7284
|
});
|
|
7226
7285
|
}
|
|
@@ -7300,7 +7359,7 @@ var makeGlobalFetchApply = (checkInEffect) => fn(`globalFetch${checkInEffect ? "
|
|
|
7300
7359
|
if (!fetchSymbol) return;
|
|
7301
7360
|
const effectVersion = typeParser.supportedEffect();
|
|
7302
7361
|
const packageName = effectVersion === "v3" ? "@effect/platform" : "effect/unstable/http";
|
|
7303
|
-
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}\`.`;
|
|
7304
7363
|
const nodeToVisit = [];
|
|
7305
7364
|
const appendNodeToVisit = (node) => {
|
|
7306
7365
|
nodeToVisit.push(node);
|
|
@@ -7373,7 +7432,7 @@ var makeGlobalRandomApply = (checkInEffect) => fn(`globalRandom${checkInEffect ?
|
|
|
7373
7432
|
if (inEffect !== checkInEffect) continue;
|
|
7374
7433
|
report({
|
|
7375
7434
|
location: node,
|
|
7376
|
-
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.",
|
|
7377
7436
|
fixes: []
|
|
7378
7437
|
});
|
|
7379
7438
|
}
|
|
@@ -7404,12 +7463,12 @@ var globalRandom = createDiagnostic({
|
|
|
7404
7463
|
// src/diagnostics/globalTimersInEffect.ts
|
|
7405
7464
|
var timerAlternatives = {
|
|
7406
7465
|
"setTimeout": {
|
|
7407
|
-
inEffect: "
|
|
7408
|
-
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."
|
|
7409
7468
|
},
|
|
7410
7469
|
"setInterval": {
|
|
7411
|
-
inEffect: "
|
|
7412
|
-
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."
|
|
7413
7472
|
}
|
|
7414
7473
|
};
|
|
7415
7474
|
var makeGlobalTimersApply = (checkInEffect) => fn(`globalTimers${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
@@ -7651,7 +7710,7 @@ var instanceOfSchema = createDiagnostic({
|
|
|
7651
7710
|
if (isSchemaType._tag === "Some") {
|
|
7652
7711
|
report({
|
|
7653
7712
|
location: node,
|
|
7654
|
-
messageText: "
|
|
7713
|
+
messageText: "This code uses `instanceof` with an Effect Schema type. `Schema.is` is the schema-aware runtime check for this case.",
|
|
7655
7714
|
fixes: [{
|
|
7656
7715
|
fixName: "instanceOfSchema_fix",
|
|
7657
7716
|
description: "Replace with Schema.is",
|
|
@@ -7921,7 +7980,7 @@ var leakingRequirements = createDiagnostic({
|
|
|
7921
7980
|
location: node,
|
|
7922
7981
|
messageText: `Methods of this Service require \`${requirementsStr}\` from every caller.
|
|
7923
7982
|
|
|
7924
|
-
|
|
7983
|
+
The requirement becomes part of the public service surface instead of remaining internal to Layer implementation.
|
|
7925
7984
|
|
|
7926
7985
|
Resolve these dependencies at Layer creation and provide them to each method, so the service's type reflects its purpose, not its implementation.
|
|
7927
7986
|
|
|
@@ -8118,7 +8177,7 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
8118
8177
|
).trim() : "";
|
|
8119
8178
|
report({
|
|
8120
8179
|
location: flow2.node,
|
|
8121
|
-
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.`,
|
|
8122
8181
|
fixes: [{
|
|
8123
8182
|
fixName: "missedPipeableOpportunity_fix",
|
|
8124
8183
|
description: "Convert to pipe style",
|
|
@@ -8199,7 +8258,7 @@ var missingEffectContext = createDiagnostic({
|
|
|
8199
8258
|
(missingTypes) => missingTypes.length > 0 ? report(
|
|
8200
8259
|
{
|
|
8201
8260
|
location: node,
|
|
8202
|
-
messageText: `
|
|
8261
|
+
messageText: `This Effect requires a service that is missing from the expected Effect context: \`${sortTypes(missingTypes).map((_) => typeChecker.typeToString(_)).join(" | ")}\`.`,
|
|
8203
8262
|
fixes: []
|
|
8204
8263
|
}
|
|
8205
8264
|
) : void 0
|
|
@@ -8550,7 +8609,7 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
8550
8609
|
}];
|
|
8551
8610
|
report({
|
|
8552
8611
|
location: unwrapped,
|
|
8553
|
-
messageText:
|
|
8612
|
+
messageText: "This Effect never succeeds; using `return yield*` preserves a definitive generator exit point for type narrowing and tooling support.",
|
|
8554
8613
|
fixes: fix
|
|
8555
8614
|
});
|
|
8556
8615
|
}
|
|
@@ -8606,7 +8665,7 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
8606
8665
|
brokenGenerators.forEach(
|
|
8607
8666
|
(pos) => report({
|
|
8608
8667
|
location: { pos, end: pos + "function".length },
|
|
8609
|
-
messageText: `
|
|
8668
|
+
messageText: "This uses `yield` for an `Effect` value. `yield*` is the Effect-aware form in this context.",
|
|
8610
8669
|
fixes: []
|
|
8611
8670
|
})
|
|
8612
8671
|
);
|
|
@@ -8628,7 +8687,7 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
8628
8687
|
}] : [];
|
|
8629
8688
|
report({
|
|
8630
8689
|
location: node,
|
|
8631
|
-
messageText: `
|
|
8690
|
+
messageText: "This uses `yield` for an `Effect` value. `yield*` is the Effect-aware form in this context.",
|
|
8632
8691
|
fixes: fix
|
|
8633
8692
|
});
|
|
8634
8693
|
});
|
|
@@ -8696,7 +8755,7 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
8696
8755
|
if (chunk.length < 2) continue;
|
|
8697
8756
|
report({
|
|
8698
8757
|
location: chunk[0].node,
|
|
8699
|
-
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.",
|
|
8700
8759
|
fixes: [{
|
|
8701
8760
|
fixName: "multipleEffectProvide_fix",
|
|
8702
8761
|
description: "Combine into a single provide",
|
|
@@ -8786,7 +8845,7 @@ var nodeBuiltinImport = createDiagnostic({
|
|
|
8786
8845
|
if (match2) {
|
|
8787
8846
|
report({
|
|
8788
8847
|
location: statement.moduleSpecifier,
|
|
8789
|
-
messageText: `
|
|
8848
|
+
messageText: `This module reference uses the \`${match2.module}\` module, the corresponding Effect API is \`${match2.alternative}\` from \`${match2.package}\`.`,
|
|
8790
8849
|
fixes: []
|
|
8791
8850
|
});
|
|
8792
8851
|
}
|
|
@@ -8799,7 +8858,7 @@ var nodeBuiltinImport = createDiagnostic({
|
|
|
8799
8858
|
if (match2) {
|
|
8800
8859
|
report({
|
|
8801
8860
|
location: arg,
|
|
8802
|
-
messageText: `
|
|
8861
|
+
messageText: `This module reference uses the \`${match2.module}\` module, the corresponding Effect API is \`${match2.alternative}\` from \`${match2.package}\`.`,
|
|
8803
8862
|
fixes: []
|
|
8804
8863
|
});
|
|
8805
8864
|
}
|
|
@@ -8853,7 +8912,7 @@ var nonObjectEffectServiceType = createDiagnostic({
|
|
|
8853
8912
|
const propertyValue = property.initializer;
|
|
8854
8913
|
const errorToReport = {
|
|
8855
8914
|
location: property.name,
|
|
8856
|
-
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.",
|
|
8857
8916
|
fixes: []
|
|
8858
8917
|
};
|
|
8859
8918
|
if (propertyName === "succeed") {
|
|
@@ -9615,7 +9674,7 @@ var outdatedApi = createDiagnostic({
|
|
|
9615
9674
|
hasReported = true;
|
|
9616
9675
|
report({
|
|
9617
9676
|
location: propertyAccess.name,
|
|
9618
|
-
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.`,
|
|
9619
9678
|
fixes: []
|
|
9620
9679
|
});
|
|
9621
9680
|
}
|
|
@@ -9658,7 +9717,7 @@ var outdatedApi = createDiagnostic({
|
|
|
9658
9717
|
if (hasReported) {
|
|
9659
9718
|
report({
|
|
9660
9719
|
location: { pos: 0, end: 0 },
|
|
9661
|
-
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.",
|
|
9662
9721
|
fixes: []
|
|
9663
9722
|
});
|
|
9664
9723
|
}
|
|
@@ -10903,7 +10962,7 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
10903
10962
|
};
|
|
10904
10963
|
report({
|
|
10905
10964
|
location: member,
|
|
10906
|
-
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.",
|
|
10907
10966
|
fixes: (member.body ? [fixAsStaticNew] : []).concat([{
|
|
10908
10967
|
fixName: "overriddenSchemaConstructor_fix",
|
|
10909
10968
|
description: "Remove the constructor override",
|
|
@@ -11025,7 +11084,7 @@ var preferSchemaOverJson = createDiagnostic({
|
|
|
11025
11084
|
if (isSome2(match2)) {
|
|
11026
11085
|
report({
|
|
11027
11086
|
location: match2.value,
|
|
11028
|
-
messageText: "
|
|
11087
|
+
messageText: "This code uses `JSON.parse` or `JSON.stringify`. Effect Schema provides Effect-aware APIs for JSON parsing and stringifying.",
|
|
11029
11088
|
fixes: []
|
|
11030
11089
|
});
|
|
11031
11090
|
}
|
|
@@ -11143,9 +11202,7 @@ var returnEffectInGen = createDiagnostic({
|
|
|
11143
11202
|
}] : [];
|
|
11144
11203
|
report({
|
|
11145
11204
|
location: node,
|
|
11146
|
-
messageText:
|
|
11147
|
-
Maybe you wanted to return yield* instead?
|
|
11148
|
-
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.",
|
|
11149
11206
|
fixes: fix
|
|
11150
11207
|
});
|
|
11151
11208
|
}),
|
|
@@ -11300,9 +11357,7 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
11300
11357
|
);
|
|
11301
11358
|
});
|
|
11302
11359
|
const v4MethodName = `${isEffectRunCall.value.methodName}With`;
|
|
11303
|
-
const messageText = supportedEffect === "v4" ?
|
|
11304
|
-
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.
|
|
11305
|
-
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}\`.`;
|
|
11306
11361
|
report({
|
|
11307
11362
|
location: node.expression,
|
|
11308
11363
|
messageText,
|
|
@@ -11315,7 +11370,7 @@ Consider extracting the Runtime by using for example Effect.runtime and then use
|
|
|
11315
11370
|
} else {
|
|
11316
11371
|
report({
|
|
11317
11372
|
location: node.expression,
|
|
11318
|
-
messageText:
|
|
11373
|
+
messageText: `\`${nodeText}\` is called inside an existing Effect context. Here, the inner Effect can be used directly.`,
|
|
11319
11374
|
fixes: []
|
|
11320
11375
|
});
|
|
11321
11376
|
}
|
|
@@ -11370,7 +11425,7 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
11370
11425
|
const otherProperties = arg.properties.filter((prop) => prop !== tagProperty);
|
|
11371
11426
|
report({
|
|
11372
11427
|
location: node,
|
|
11373
|
-
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.",
|
|
11374
11429
|
fixes: [{
|
|
11375
11430
|
fixName: "schemaStructWithTag_fix",
|
|
11376
11431
|
description: "Replace with Schema.TaggedStruct",
|
|
@@ -11463,7 +11518,7 @@ var schemaSyncInEffect = createDiagnostic({
|
|
|
11463
11518
|
const effectMethodName = syncToEffectMethod[isSchemaSyncCall.value.methodName];
|
|
11464
11519
|
report({
|
|
11465
11520
|
location: node.expression,
|
|
11466
|
-
messageText:
|
|
11521
|
+
messageText: `\`${nodeText}\` is used inside an Effect generator. \`Schema.${effectMethodName}\` preserves the typed Effect error channel for this operation without throwing.`,
|
|
11467
11522
|
fixes: []
|
|
11468
11523
|
});
|
|
11469
11524
|
}
|
|
@@ -11523,7 +11578,7 @@ var schemaUnionOfLiterals = createDiagnostic({
|
|
|
11523
11578
|
const schemaLiteralExpression = firstLiteralCall.expression;
|
|
11524
11579
|
report({
|
|
11525
11580
|
location: node,
|
|
11526
|
-
messageText: "
|
|
11581
|
+
messageText: "This `Schema.Union` contains multiple `Schema.Literal` members and can be simplified to a single `Schema.Literal` call.",
|
|
11527
11582
|
fixes: [{
|
|
11528
11583
|
fixName: "schemaUnionOfLiterals_fix",
|
|
11529
11584
|
description: "Replace with a single Schema.Literal call",
|
|
@@ -11586,8 +11641,7 @@ var scopeInLayerEffect = createDiagnostic({
|
|
|
11586
11641
|
map4(
|
|
11587
11642
|
() => report({
|
|
11588
11643
|
location: node,
|
|
11589
|
-
messageText: `
|
|
11590
|
-
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.",
|
|
11591
11645
|
fixes: methodIdentifier ? [{
|
|
11592
11646
|
fixName: "scopeInLayerEffect_scoped",
|
|
11593
11647
|
description: "Use scoped for Layer creation",
|
|
@@ -11687,7 +11741,7 @@ var serviceNotAsClass = createDiagnostic({
|
|
|
11687
11741
|
const shapeText = typeArgs.length > 0 ? typeArgs.map((t) => sourceFile.text.substring(ts.getTokenPosOfNode(t, sourceFile), t.end)).join(", ") : "Shape";
|
|
11688
11742
|
report({
|
|
11689
11743
|
location: callExpr,
|
|
11690
|
-
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, "")}") {}\`.`,
|
|
11691
11745
|
fixes: [{
|
|
11692
11746
|
fixName: "serviceNotAsClass",
|
|
11693
11747
|
description: `Convert to class declaration`,
|
|
@@ -11900,7 +11954,7 @@ var tryCatchInEffectGen = createDiagnostic({
|
|
|
11900
11954
|
map4(() => {
|
|
11901
11955
|
report({
|
|
11902
11956
|
location: node,
|
|
11903
|
-
messageText: `
|
|
11957
|
+
messageText: `This Effect generator contains \`try/catch\`; in this context, error handling is expressed with Effect APIs such as ${alternatives.join(", ")}).`,
|
|
11904
11958
|
fixes: []
|
|
11905
11959
|
});
|
|
11906
11960
|
}),
|
|
@@ -11961,8 +12015,7 @@ var unknownInEffectCatch = createDiagnostic({
|
|
|
11961
12015
|
);
|
|
11962
12016
|
report({
|
|
11963
12017
|
location: node.expression,
|
|
11964
|
-
messageText: `The
|
|
11965
|
-
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\`.`,
|
|
11966
12019
|
fixes: []
|
|
11967
12020
|
});
|
|
11968
12021
|
}
|
|
@@ -12059,7 +12112,7 @@ var unnecessaryFailYieldableError = createDiagnostic({
|
|
|
12059
12112
|
map4(
|
|
12060
12113
|
() => report({
|
|
12061
12114
|
location: node,
|
|
12062
|
-
messageText:
|
|
12115
|
+
messageText: "This `yield* Effect.fail(...)` passes a yieldable error value. `yield*` represents that value directly without wrapping it in `Effect.fail`.",
|
|
12063
12116
|
fixes: [{
|
|
12064
12117
|
fixName: "unnecessaryFailYieldableError_fix",
|
|
12065
12118
|
description: "Replace yield* Effect.fail with yield*",
|
|
@@ -12164,7 +12217,7 @@ var unnecessaryPipeChain = createDiagnostic({
|
|
|
12164
12217
|
map4(({ innerCall, pipeCall }) => {
|
|
12165
12218
|
report({
|
|
12166
12219
|
location: node,
|
|
12167
|
-
messageText: `
|
|
12220
|
+
messageText: "This expression contains chained `pipe` calls that can be simplified to a single `pipe` call.",
|
|
12168
12221
|
fixes: [{
|
|
12169
12222
|
fixName: "unnecessaryPipeChain_fix",
|
|
12170
12223
|
description: "Rewrite as single pipe call",
|