@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/package.json
CHANGED
package/transform.js
CHANGED
|
@@ -3118,10 +3118,42 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
3118
3118
|
if (node.parent && ts.isJsxOpeningElement(node.parent) && node.parent.tagName === node) return;
|
|
3119
3119
|
if (node.parent && ts.isJsxClosingElement(node.parent) && node.parent.tagName === node) return;
|
|
3120
3120
|
if (node.parent && ts.isJsxAttribute(node.parent) && node.parent.name === node) return;
|
|
3121
|
+
if (isInsideTypeOnlyHeritageExpression(node)) return;
|
|
3121
3122
|
if (ts.isExpression(node) || ts.isTypeNode(node)) {
|
|
3122
3123
|
return typeChecker.getTypeAtLocation(node);
|
|
3123
3124
|
}
|
|
3124
3125
|
}
|
|
3126
|
+
function isInsideTypeOnlyHeritageExpression(node) {
|
|
3127
|
+
if (ts.isExpressionWithTypeArguments(node)) {
|
|
3128
|
+
return isTypeOnlyHeritageClause(node.parent);
|
|
3129
|
+
}
|
|
3130
|
+
if (!ts.isIdentifier(node) && !ts.isPropertyAccessExpression(node)) {
|
|
3131
|
+
return false;
|
|
3132
|
+
}
|
|
3133
|
+
for (let current = node.parent; current; current = current.parent) {
|
|
3134
|
+
if (ts.isPropertyAccessExpression(current)) {
|
|
3135
|
+
continue;
|
|
3136
|
+
}
|
|
3137
|
+
if (ts.isExpressionWithTypeArguments(current)) {
|
|
3138
|
+
return isTypeOnlyHeritageClause(current.parent);
|
|
3139
|
+
}
|
|
3140
|
+
return false;
|
|
3141
|
+
}
|
|
3142
|
+
return false;
|
|
3143
|
+
}
|
|
3144
|
+
function isTypeOnlyHeritageClause(node) {
|
|
3145
|
+
if (!node || !ts.isHeritageClause(node)) {
|
|
3146
|
+
return false;
|
|
3147
|
+
}
|
|
3148
|
+
const container = node.parent;
|
|
3149
|
+
if (!container) {
|
|
3150
|
+
return false;
|
|
3151
|
+
}
|
|
3152
|
+
if (ts.isInterfaceDeclaration(container)) {
|
|
3153
|
+
return true;
|
|
3154
|
+
}
|
|
3155
|
+
return ts.isClassLike(container) && node.token === ts.SyntaxKind.ImplementsKeyword;
|
|
3156
|
+
}
|
|
3125
3157
|
function resolveToGlobalSymbol(symbol3) {
|
|
3126
3158
|
if (symbol3.flags & ts.SymbolFlags.Alias) {
|
|
3127
3159
|
symbol3 = typeChecker.getAliasedSymbol(symbol3);
|
|
@@ -3445,6 +3477,14 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3445
3477
|
),
|
|
3446
3478
|
([A, E, R]) => ({ A, E, R })
|
|
3447
3479
|
);
|
|
3480
|
+
const streamVarianceStruct = (type, atLocation) => map4(
|
|
3481
|
+
all(
|
|
3482
|
+
varianceStructCovariantType(type, atLocation, "_A"),
|
|
3483
|
+
varianceStructCovariantType(type, atLocation, "_E"),
|
|
3484
|
+
varianceStructCovariantType(type, atLocation, "_R")
|
|
3485
|
+
),
|
|
3486
|
+
([A, E, R]) => ({ A, E, R })
|
|
3487
|
+
);
|
|
3448
3488
|
const layerVarianceStruct = (type, atLocation) => map4(
|
|
3449
3489
|
all(
|
|
3450
3490
|
varianceStructContravariantType(type, atLocation, "_ROut"),
|
|
@@ -3491,6 +3531,21 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3491
3531
|
"TypeParser.strictEffectType",
|
|
3492
3532
|
(type) => type
|
|
3493
3533
|
);
|
|
3534
|
+
const streamType = cachedBy(
|
|
3535
|
+
fn("TypeParser.streamType")(function* (type, atLocation) {
|
|
3536
|
+
if (supportedEffect() === "v3") {
|
|
3537
|
+
return yield* effectType(type, atLocation);
|
|
3538
|
+
}
|
|
3539
|
+
const typeIdSymbol = typeChecker.getPropertyOfType(type, "~effect/Stream");
|
|
3540
|
+
if (!typeIdSymbol) {
|
|
3541
|
+
return yield* typeParserIssue("Type is not a stream", type, atLocation);
|
|
3542
|
+
}
|
|
3543
|
+
const typeIdType = typeChecker.getTypeOfSymbolAtLocation(typeIdSymbol, atLocation);
|
|
3544
|
+
return yield* streamVarianceStruct(typeIdType, atLocation);
|
|
3545
|
+
}),
|
|
3546
|
+
"TypeParser.streamType",
|
|
3547
|
+
(type) => type
|
|
3548
|
+
);
|
|
3494
3549
|
const isEffectTypeSourceFile = cachedBy(
|
|
3495
3550
|
fn("TypeParser.isEffectTypeSourceFile")(function* (sourceFile) {
|
|
3496
3551
|
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
@@ -5226,6 +5281,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
5226
5281
|
isServiceMapTypeSourceFile,
|
|
5227
5282
|
isNodeReferenceToServiceMapModuleApi,
|
|
5228
5283
|
effectType,
|
|
5284
|
+
streamType,
|
|
5229
5285
|
strictEffectType,
|
|
5230
5286
|
layerType,
|
|
5231
5287
|
fiberType,
|
|
@@ -5453,7 +5509,7 @@ var catchAllToMapError = createDiagnostic({
|
|
|
5453
5509
|
const { failArg, failCall } = failCallInfo;
|
|
5454
5510
|
report({
|
|
5455
5511
|
location: transformation.callee,
|
|
5456
|
-
messageText:
|
|
5512
|
+
messageText: `\`Effect.mapError\` expresses the same error-type transformation more directly than \`Effect.${catchAllName}\` followed by \`Effect.fail\`.`,
|
|
5457
5513
|
fixes: [{
|
|
5458
5514
|
fixName: "catchAllToMapError_fix",
|
|
5459
5515
|
description: "Replace with Effect.mapError",
|
|
@@ -5517,7 +5573,7 @@ var catchUnfailableEffect = createDiagnostic({
|
|
|
5517
5573
|
if (E.flags & ts.TypeFlags.Never) {
|
|
5518
5574
|
report({
|
|
5519
5575
|
location: transformation.callee,
|
|
5520
|
-
messageText:
|
|
5576
|
+
messageText: "The previous Effect does not fail, so this error-handling branch will never run.",
|
|
5521
5577
|
fixes: []
|
|
5522
5578
|
});
|
|
5523
5579
|
}
|
|
@@ -5580,7 +5636,7 @@ var classSelfMismatch = createDiagnostic({
|
|
|
5580
5636
|
if (actualName !== expectedName) {
|
|
5581
5637
|
report({
|
|
5582
5638
|
location: selfTypeNode,
|
|
5583
|
-
messageText: `Self type parameter should be
|
|
5639
|
+
messageText: `The \`Self\` type parameter for this class should be \`${expectedName}\`.`,
|
|
5584
5640
|
fixes: [{
|
|
5585
5641
|
fixName: "classSelfMismatch_fix",
|
|
5586
5642
|
description: `Replace '${actualName}' with '${expectedName}'`,
|
|
@@ -5770,7 +5826,7 @@ var deterministicKeys = createDiagnostic({
|
|
|
5770
5826
|
if (actualIdentifier !== expectedKey) {
|
|
5771
5827
|
report({
|
|
5772
5828
|
location: keyStringLiteral,
|
|
5773
|
-
messageText: `
|
|
5829
|
+
messageText: `This key does not match the deterministic key for this declaration. The expected key is \`${expectedKey}\`.`,
|
|
5774
5830
|
fixes: [{
|
|
5775
5831
|
fixName: "deterministicKeys_fix",
|
|
5776
5832
|
description: `Replace '${actualIdentifier}' with '${expectedKey}'`,
|
|
@@ -5809,9 +5865,8 @@ var duplicatePackage = createDiagnostic({
|
|
|
5809
5865
|
const versions = Object.keys(resolvedPackages[packageName]);
|
|
5810
5866
|
report({
|
|
5811
5867
|
location: sourceFile.statements[0],
|
|
5812
|
-
messageText: `
|
|
5813
|
-
|
|
5814
|
-
If this is intended set the LSP config "allowedDuplicatedPackages" to ${JSON.stringify(options.allowedDuplicatedPackages.concat([packageName]))}.
|
|
5868
|
+
messageText: `Multiple versions of package \`${packageName}\` were detected: ${versions.join(", ")}. Package duplication can change runtime identity and type equality across Effect modules.
|
|
5869
|
+
If this is intentional, set the LSP config \`allowedDuplicatedPackages\` to ${JSON.stringify(options.allowedDuplicatedPackages.concat([packageName]))}.
|
|
5815
5870
|
|
|
5816
5871
|
${versions.map((version) => `- found ${version} at ${resolvedPackages[packageName][version]}`).join("\n")}`,
|
|
5817
5872
|
fixes: []
|
|
@@ -5919,7 +5974,7 @@ var effectFnIife = createDiagnostic({
|
|
|
5919
5974
|
const traceExpressionText = traceExpression ? sourceFile.text.slice(traceExpression.pos, traceExpression.end) : void 0;
|
|
5920
5975
|
report({
|
|
5921
5976
|
location: node,
|
|
5922
|
-
messageText:
|
|
5977
|
+
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` : ``}.`,
|
|
5923
5978
|
fixes
|
|
5924
5979
|
});
|
|
5925
5980
|
}
|
|
@@ -6004,7 +6059,7 @@ var effectFnImplicitAny = createDiagnostic({
|
|
|
6004
6059
|
const parameterName = getParameterName(ts, parameter.name);
|
|
6005
6060
|
report({
|
|
6006
6061
|
location: parameter.name,
|
|
6007
|
-
messageText: `Parameter
|
|
6062
|
+
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.`,
|
|
6008
6063
|
fixes: []
|
|
6009
6064
|
});
|
|
6010
6065
|
}
|
|
@@ -6600,7 +6655,7 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
6600
6655
|
const expectedSignature = generateExpectedSignature();
|
|
6601
6656
|
report({
|
|
6602
6657
|
location: nameIdentifier ?? targetNode,
|
|
6603
|
-
messageText: `
|
|
6658
|
+
messageText: `This expression can be rewritten in the reusable function form \`${expectedSignature}\`.`,
|
|
6604
6659
|
fixes
|
|
6605
6660
|
});
|
|
6606
6661
|
}
|
|
@@ -6812,7 +6867,7 @@ var effectMapVoid = createDiagnostic({
|
|
|
6812
6867
|
if (isNone2(match2)) continue;
|
|
6813
6868
|
report({
|
|
6814
6869
|
location: node.expression,
|
|
6815
|
-
messageText: "
|
|
6870
|
+
messageText: "This expression discards the success value through mapping. `Effect.asVoid` represents that form directly.",
|
|
6816
6871
|
fixes: [{
|
|
6817
6872
|
fixName: "effectMapVoid_fix",
|
|
6818
6873
|
description: "Replace with Effect.asVoid",
|
|
@@ -6867,7 +6922,7 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
6867
6922
|
if (!tsUtils.isVoidExpression(argument)) continue;
|
|
6868
6923
|
report({
|
|
6869
6924
|
location: node,
|
|
6870
|
-
messageText: "Effect.void
|
|
6925
|
+
messageText: "`Effect.void` represents the same outcome as `Effect.succeed(undefined)` or `Effect.succeed(void 0)`.",
|
|
6871
6926
|
fixes: [{
|
|
6872
6927
|
fixName: "effectSucceedWithVoid_fix",
|
|
6873
6928
|
description: "Replace with Effect.void",
|
|
@@ -6929,7 +6984,7 @@ var extendsNativeError = createDiagnostic({
|
|
|
6929
6984
|
if (isNativeError) {
|
|
6930
6985
|
report({
|
|
6931
6986
|
location: node.name ?? typeExpression,
|
|
6932
|
-
messageText: "
|
|
6987
|
+
messageText: "This class extends the native `Error` type directly. Untagged native errors lose distinction in the Effect failure channel.",
|
|
6933
6988
|
fixes: []
|
|
6934
6989
|
});
|
|
6935
6990
|
}
|
|
@@ -6974,7 +7029,12 @@ var floatingEffect = createDiagnostic({
|
|
|
6974
7029
|
if (!isFloatingExpression(node)) continue;
|
|
6975
7030
|
const type = typeCheckerUtils.getTypeAtLocation(node.expression);
|
|
6976
7031
|
if (!type) continue;
|
|
6977
|
-
const effect = yield* option(
|
|
7032
|
+
const effect = yield* option(
|
|
7033
|
+
pipe(
|
|
7034
|
+
typeParser.effectType(type, node.expression),
|
|
7035
|
+
orElse2(() => typeParser.streamType(type, node.expression))
|
|
7036
|
+
)
|
|
7037
|
+
);
|
|
6978
7038
|
if (isSome2(effect)) {
|
|
6979
7039
|
const allowedFloatingEffects = yield* pipe(
|
|
6980
7040
|
typeParser.fiberType(type, node.expression),
|
|
@@ -6983,10 +7043,9 @@ var floatingEffect = createDiagnostic({
|
|
|
6983
7043
|
);
|
|
6984
7044
|
if (isNone2(allowedFloatingEffects)) {
|
|
6985
7045
|
const isStrictEffect = yield* option(typeParser.strictEffectType(type, node.expression));
|
|
6986
|
-
const name = isSome2(isStrictEffect) ? "Effect" : "Effect-able " + typeChecker.typeToString(type);
|
|
6987
7046
|
report({
|
|
6988
7047
|
location: node,
|
|
6989
|
-
messageText:
|
|
7048
|
+
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.`,
|
|
6990
7049
|
fixes: []
|
|
6991
7050
|
});
|
|
6992
7051
|
}
|
|
@@ -7081,7 +7140,7 @@ var makeGlobalConsoleApply = (checkInEffect) => fn(`globalConsole${checkInEffect
|
|
|
7081
7140
|
if (inEffect !== checkInEffect) continue;
|
|
7082
7141
|
report({
|
|
7083
7142
|
location: node,
|
|
7084
|
-
messageText: checkInEffect ? `
|
|
7143
|
+
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}\`.`,
|
|
7085
7144
|
fixes: []
|
|
7086
7145
|
});
|
|
7087
7146
|
}
|
|
@@ -7130,10 +7189,10 @@ var makeGlobalDateApply = (checkInEffect) => fn(`globalDate${checkInEffect ? "In
|
|
|
7130
7189
|
let objectNode;
|
|
7131
7190
|
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.idText(node.expression.name) === "now") {
|
|
7132
7191
|
objectNode = node.expression.expression;
|
|
7133
|
-
messageText = checkInEffect ? "
|
|
7192
|
+
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.";
|
|
7134
7193
|
} else if (ts.isNewExpression(node)) {
|
|
7135
7194
|
objectNode = node.expression;
|
|
7136
|
-
messageText = checkInEffect ? "
|
|
7195
|
+
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.";
|
|
7137
7196
|
}
|
|
7138
7197
|
if (!messageText || !objectNode) continue;
|
|
7139
7198
|
const symbol3 = typeChecker.getSymbolAtLocation(objectNode);
|
|
@@ -7216,7 +7275,7 @@ var globalErrorInEffectCatch = createDiagnostic({
|
|
|
7216
7275
|
);
|
|
7217
7276
|
report({
|
|
7218
7277
|
location: node.expression,
|
|
7219
|
-
messageText: `The
|
|
7278
|
+
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.`,
|
|
7220
7279
|
fixes: []
|
|
7221
7280
|
});
|
|
7222
7281
|
}
|
|
@@ -7296,7 +7355,7 @@ var makeGlobalFetchApply = (checkInEffect) => fn(`globalFetch${checkInEffect ? "
|
|
|
7296
7355
|
if (!fetchSymbol) return;
|
|
7297
7356
|
const effectVersion = typeParser.supportedEffect();
|
|
7298
7357
|
const packageName = effectVersion === "v3" ? "@effect/platform" : "effect/unstable/http";
|
|
7299
|
-
const messageText = checkInEffect ? `
|
|
7358
|
+
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}\`.`;
|
|
7300
7359
|
const nodeToVisit = [];
|
|
7301
7360
|
const appendNodeToVisit = (node) => {
|
|
7302
7361
|
nodeToVisit.push(node);
|
|
@@ -7369,7 +7428,7 @@ var makeGlobalRandomApply = (checkInEffect) => fn(`globalRandom${checkInEffect ?
|
|
|
7369
7428
|
if (inEffect !== checkInEffect) continue;
|
|
7370
7429
|
report({
|
|
7371
7430
|
location: node,
|
|
7372
|
-
messageText: checkInEffect ? "
|
|
7431
|
+
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.",
|
|
7373
7432
|
fixes: []
|
|
7374
7433
|
});
|
|
7375
7434
|
}
|
|
@@ -7400,12 +7459,12 @@ var globalRandom = createDiagnostic({
|
|
|
7400
7459
|
// src/diagnostics/globalTimersInEffect.ts
|
|
7401
7460
|
var timerAlternatives = {
|
|
7402
7461
|
"setTimeout": {
|
|
7403
|
-
inEffect: "
|
|
7404
|
-
outsideEffect: "
|
|
7462
|
+
inEffect: "This Effect code uses `setTimeout`, the corresponding timer API in this context is `Effect.sleep or Schedule` from Effect.",
|
|
7463
|
+
outsideEffect: "This code uses `setTimeout`, the corresponding Effect timer API is `Effect.sleep or Schedule` from Effect."
|
|
7405
7464
|
},
|
|
7406
7465
|
"setInterval": {
|
|
7407
|
-
inEffect: "
|
|
7408
|
-
outsideEffect: "
|
|
7466
|
+
inEffect: "This Effect code uses `setInterval`, the corresponding timer API in this context is `Schedule or Effect.repeat` from Effect.",
|
|
7467
|
+
outsideEffect: "This code uses `setInterval`, the corresponding Effect timer API is `Schedule or Effect.repeat` from Effect."
|
|
7409
7468
|
}
|
|
7410
7469
|
};
|
|
7411
7470
|
var makeGlobalTimersApply = (checkInEffect) => fn(`globalTimers${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
@@ -7647,7 +7706,7 @@ var instanceOfSchema = createDiagnostic({
|
|
|
7647
7706
|
if (isSchemaType._tag === "Some") {
|
|
7648
7707
|
report({
|
|
7649
7708
|
location: node,
|
|
7650
|
-
messageText: "
|
|
7709
|
+
messageText: "This code uses `instanceof` with an Effect Schema type. `Schema.is` is the schema-aware runtime check for this case.",
|
|
7651
7710
|
fixes: [{
|
|
7652
7711
|
fixName: "instanceOfSchema_fix",
|
|
7653
7712
|
description: "Replace with Schema.is",
|
|
@@ -7917,7 +7976,7 @@ var leakingRequirements = createDiagnostic({
|
|
|
7917
7976
|
location: node,
|
|
7918
7977
|
messageText: `Methods of this Service require \`${requirementsStr}\` from every caller.
|
|
7919
7978
|
|
|
7920
|
-
|
|
7979
|
+
The requirement becomes part of the public service surface instead of remaining internal to Layer implementation.
|
|
7921
7980
|
|
|
7922
7981
|
Resolve these dependencies at Layer creation and provide them to each method, so the service's type reflects its purpose, not its implementation.
|
|
7923
7982
|
|
|
@@ -8114,7 +8173,7 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
8114
8173
|
).trim() : "";
|
|
8115
8174
|
report({
|
|
8116
8175
|
location: flow2.node,
|
|
8117
|
-
messageText: `
|
|
8176
|
+
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.`,
|
|
8118
8177
|
fixes: [{
|
|
8119
8178
|
fixName: "missedPipeableOpportunity_fix",
|
|
8120
8179
|
description: "Convert to pipe style",
|
|
@@ -8195,7 +8254,7 @@ var missingEffectContext = createDiagnostic({
|
|
|
8195
8254
|
(missingTypes) => missingTypes.length > 0 ? report(
|
|
8196
8255
|
{
|
|
8197
8256
|
location: node,
|
|
8198
|
-
messageText: `
|
|
8257
|
+
messageText: `This Effect requires a service that is missing from the expected Effect context: \`${sortTypes(missingTypes).map((_) => typeChecker.typeToString(_)).join(" | ")}\`.`,
|
|
8199
8258
|
fixes: []
|
|
8200
8259
|
}
|
|
8201
8260
|
) : void 0
|
|
@@ -8546,7 +8605,7 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
8546
8605
|
}];
|
|
8547
8606
|
report({
|
|
8548
8607
|
location: unwrapped,
|
|
8549
|
-
messageText:
|
|
8608
|
+
messageText: "This Effect never succeeds; using `return yield*` preserves a definitive generator exit point for type narrowing and tooling support.",
|
|
8550
8609
|
fixes: fix
|
|
8551
8610
|
});
|
|
8552
8611
|
}
|
|
@@ -8602,7 +8661,7 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
8602
8661
|
brokenGenerators.forEach(
|
|
8603
8662
|
(pos) => report({
|
|
8604
8663
|
location: { pos, end: pos + "function".length },
|
|
8605
|
-
messageText: `
|
|
8664
|
+
messageText: "This uses `yield` for an `Effect` value. `yield*` is the Effect-aware form in this context.",
|
|
8606
8665
|
fixes: []
|
|
8607
8666
|
})
|
|
8608
8667
|
);
|
|
@@ -8624,7 +8683,7 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
8624
8683
|
}] : [];
|
|
8625
8684
|
report({
|
|
8626
8685
|
location: node,
|
|
8627
|
-
messageText: `
|
|
8686
|
+
messageText: "This uses `yield` for an `Effect` value. `yield*` is the Effect-aware form in this context.",
|
|
8628
8687
|
fixes: fix
|
|
8629
8688
|
});
|
|
8630
8689
|
});
|
|
@@ -8692,7 +8751,7 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
8692
8751
|
if (chunk.length < 2) continue;
|
|
8693
8752
|
report({
|
|
8694
8753
|
location: chunk[0].node,
|
|
8695
|
-
messageText: "
|
|
8754
|
+
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.",
|
|
8696
8755
|
fixes: [{
|
|
8697
8756
|
fixName: "multipleEffectProvide_fix",
|
|
8698
8757
|
description: "Combine into a single provide",
|
|
@@ -8782,7 +8841,7 @@ var nodeBuiltinImport = createDiagnostic({
|
|
|
8782
8841
|
if (match2) {
|
|
8783
8842
|
report({
|
|
8784
8843
|
location: statement.moduleSpecifier,
|
|
8785
|
-
messageText: `
|
|
8844
|
+
messageText: `This module reference uses the \`${match2.module}\` module, the corresponding Effect API is \`${match2.alternative}\` from \`${match2.package}\`.`,
|
|
8786
8845
|
fixes: []
|
|
8787
8846
|
});
|
|
8788
8847
|
}
|
|
@@ -8795,7 +8854,7 @@ var nodeBuiltinImport = createDiagnostic({
|
|
|
8795
8854
|
if (match2) {
|
|
8796
8855
|
report({
|
|
8797
8856
|
location: arg,
|
|
8798
|
-
messageText: `
|
|
8857
|
+
messageText: `This module reference uses the \`${match2.module}\` module, the corresponding Effect API is \`${match2.alternative}\` from \`${match2.package}\`.`,
|
|
8799
8858
|
fixes: []
|
|
8800
8859
|
});
|
|
8801
8860
|
}
|
|
@@ -8849,7 +8908,7 @@ var nonObjectEffectServiceType = createDiagnostic({
|
|
|
8849
8908
|
const propertyValue = property.initializer;
|
|
8850
8909
|
const errorToReport = {
|
|
8851
8910
|
location: property.name,
|
|
8852
|
-
messageText: "Effect.Service
|
|
8911
|
+
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.",
|
|
8853
8912
|
fixes: []
|
|
8854
8913
|
};
|
|
8855
8914
|
if (propertyName === "succeed") {
|
|
@@ -9611,7 +9670,7 @@ var outdatedApi = createDiagnostic({
|
|
|
9611
9670
|
hasReported = true;
|
|
9612
9671
|
report({
|
|
9613
9672
|
location: propertyAccess.name,
|
|
9614
|
-
messageText:
|
|
9673
|
+
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.`,
|
|
9615
9674
|
fixes: []
|
|
9616
9675
|
});
|
|
9617
9676
|
}
|
|
@@ -9654,7 +9713,7 @@ var outdatedApi = createDiagnostic({
|
|
|
9654
9713
|
if (hasReported) {
|
|
9655
9714
|
report({
|
|
9656
9715
|
location: { pos: 0, end: 0 },
|
|
9657
|
-
messageText: "This project targets Effect v4, but
|
|
9716
|
+
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.",
|
|
9658
9717
|
fixes: []
|
|
9659
9718
|
});
|
|
9660
9719
|
}
|
|
@@ -10899,7 +10958,7 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
10899
10958
|
};
|
|
10900
10959
|
report({
|
|
10901
10960
|
location: member,
|
|
10902
|
-
messageText: "
|
|
10961
|
+
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.",
|
|
10903
10962
|
fixes: (member.body ? [fixAsStaticNew] : []).concat([{
|
|
10904
10963
|
fixName: "overriddenSchemaConstructor_fix",
|
|
10905
10964
|
description: "Remove the constructor override",
|
|
@@ -11021,7 +11080,7 @@ var preferSchemaOverJson = createDiagnostic({
|
|
|
11021
11080
|
if (isSome2(match2)) {
|
|
11022
11081
|
report({
|
|
11023
11082
|
location: match2.value,
|
|
11024
|
-
messageText: "
|
|
11083
|
+
messageText: "This code uses `JSON.parse` or `JSON.stringify`. Effect Schema provides Effect-aware APIs for JSON parsing and stringifying.",
|
|
11025
11084
|
fixes: []
|
|
11026
11085
|
});
|
|
11027
11086
|
}
|
|
@@ -11139,9 +11198,7 @@ var returnEffectInGen = createDiagnostic({
|
|
|
11139
11198
|
}] : [];
|
|
11140
11199
|
report({
|
|
11141
11200
|
location: node,
|
|
11142
|
-
messageText:
|
|
11143
|
-
Maybe you wanted to return yield* instead?
|
|
11144
|
-
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.`,
|
|
11201
|
+
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.",
|
|
11145
11202
|
fixes: fix
|
|
11146
11203
|
});
|
|
11147
11204
|
}),
|
|
@@ -11296,9 +11353,7 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
11296
11353
|
);
|
|
11297
11354
|
});
|
|
11298
11355
|
const v4MethodName = `${isEffectRunCall.value.methodName}With`;
|
|
11299
|
-
const messageText = supportedEffect === "v4" ?
|
|
11300
|
-
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.
|
|
11301
|
-
Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`;
|
|
11356
|
+
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}\`.`;
|
|
11302
11357
|
report({
|
|
11303
11358
|
location: node.expression,
|
|
11304
11359
|
messageText,
|
|
@@ -11311,7 +11366,7 @@ Consider extracting the Runtime by using for example Effect.runtime and then use
|
|
|
11311
11366
|
} else {
|
|
11312
11367
|
report({
|
|
11313
11368
|
location: node.expression,
|
|
11314
|
-
messageText:
|
|
11369
|
+
messageText: `\`${nodeText}\` is called inside an existing Effect context. Here, the inner Effect can be used directly.`,
|
|
11315
11370
|
fixes: []
|
|
11316
11371
|
});
|
|
11317
11372
|
}
|
|
@@ -11366,7 +11421,7 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
11366
11421
|
const otherProperties = arg.properties.filter((prop) => prop !== tagProperty);
|
|
11367
11422
|
report({
|
|
11368
11423
|
location: node,
|
|
11369
|
-
messageText: "Schema.Struct
|
|
11424
|
+
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.",
|
|
11370
11425
|
fixes: [{
|
|
11371
11426
|
fixName: "schemaStructWithTag_fix",
|
|
11372
11427
|
description: "Replace with Schema.TaggedStruct",
|
|
@@ -11459,7 +11514,7 @@ var schemaSyncInEffect = createDiagnostic({
|
|
|
11459
11514
|
const effectMethodName = syncToEffectMethod[isSchemaSyncCall.value.methodName];
|
|
11460
11515
|
report({
|
|
11461
11516
|
location: node.expression,
|
|
11462
|
-
messageText:
|
|
11517
|
+
messageText: `\`${nodeText}\` is used inside an Effect generator. \`Schema.${effectMethodName}\` preserves the typed Effect error channel for this operation without throwing.`,
|
|
11463
11518
|
fixes: []
|
|
11464
11519
|
});
|
|
11465
11520
|
}
|
|
@@ -11519,7 +11574,7 @@ var schemaUnionOfLiterals = createDiagnostic({
|
|
|
11519
11574
|
const schemaLiteralExpression = firstLiteralCall.expression;
|
|
11520
11575
|
report({
|
|
11521
11576
|
location: node,
|
|
11522
|
-
messageText: "
|
|
11577
|
+
messageText: "This `Schema.Union` contains multiple `Schema.Literal` members and can be simplified to a single `Schema.Literal` call.",
|
|
11523
11578
|
fixes: [{
|
|
11524
11579
|
fixName: "schemaUnionOfLiterals_fix",
|
|
11525
11580
|
description: "Replace with a single Schema.Literal call",
|
|
@@ -11582,8 +11637,7 @@ var scopeInLayerEffect = createDiagnostic({
|
|
|
11582
11637
|
map4(
|
|
11583
11638
|
() => report({
|
|
11584
11639
|
location: node,
|
|
11585
|
-
messageText: `
|
|
11586
|
-
Consider using "scoped" instead to get rid of the scope in the requirements.`,
|
|
11640
|
+
messageText: "This layer construction leaves `Scope` in the requirement set. The scoped API removes `Scope` from the resulting requirements.",
|
|
11587
11641
|
fixes: methodIdentifier ? [{
|
|
11588
11642
|
fixName: "scopeInLayerEffect_scoped",
|
|
11589
11643
|
description: "Use scoped for Layer creation",
|
|
@@ -11683,7 +11737,7 @@ var serviceNotAsClass = createDiagnostic({
|
|
|
11683
11737
|
const shapeText = typeArgs.length > 0 ? typeArgs.map((t) => sourceFile.text.substring(ts.getTokenPosOfNode(t, sourceFile), t.end)).join(", ") : "Shape";
|
|
11684
11738
|
report({
|
|
11685
11739
|
location: callExpr,
|
|
11686
|
-
messageText:
|
|
11740
|
+
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, "")}") {}\`.`,
|
|
11687
11741
|
fixes: [{
|
|
11688
11742
|
fixName: "serviceNotAsClass",
|
|
11689
11743
|
description: `Convert to class declaration`,
|
|
@@ -11896,7 +11950,7 @@ var tryCatchInEffectGen = createDiagnostic({
|
|
|
11896
11950
|
map4(() => {
|
|
11897
11951
|
report({
|
|
11898
11952
|
location: node,
|
|
11899
|
-
messageText: `
|
|
11953
|
+
messageText: `This Effect generator contains \`try/catch\`; in this context, error handling is expressed with Effect APIs such as ${alternatives.join(", ")}).`,
|
|
11900
11954
|
fixes: []
|
|
11901
11955
|
});
|
|
11902
11956
|
}),
|
|
@@ -11957,8 +12011,7 @@ var unknownInEffectCatch = createDiagnostic({
|
|
|
11957
12011
|
);
|
|
11958
12012
|
report({
|
|
11959
12013
|
location: node.expression,
|
|
11960
|
-
messageText: `The
|
|
11961
|
-
Consider wrapping unknown errors into Effect's Data.TaggedError for example, or narrow down the type to the specific error raised.`,
|
|
12014
|
+
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\`.`,
|
|
11962
12015
|
fixes: []
|
|
11963
12016
|
});
|
|
11964
12017
|
}
|
|
@@ -12055,7 +12108,7 @@ var unnecessaryFailYieldableError = createDiagnostic({
|
|
|
12055
12108
|
map4(
|
|
12056
12109
|
() => report({
|
|
12057
12110
|
location: node,
|
|
12058
|
-
messageText:
|
|
12111
|
+
messageText: "This `yield* Effect.fail(...)` passes a yieldable error value. `yield*` represents that value directly without wrapping it in `Effect.fail`.",
|
|
12059
12112
|
fixes: [{
|
|
12060
12113
|
fixName: "unnecessaryFailYieldableError_fix",
|
|
12061
12114
|
description: "Replace yield* Effect.fail with yield*",
|
|
@@ -12160,7 +12213,7 @@ var unnecessaryPipeChain = createDiagnostic({
|
|
|
12160
12213
|
map4(({ innerCall, pipeCall }) => {
|
|
12161
12214
|
report({
|
|
12162
12215
|
location: node,
|
|
12163
|
-
messageText: `
|
|
12216
|
+
messageText: "This expression contains chained `pipe` calls that can be simplified to a single `pipe` call.",
|
|
12164
12217
|
fixes: [{
|
|
12165
12218
|
fixName: "unnecessaryPipeChain_fix",
|
|
12166
12219
|
description: "Rewrite as single pipe call",
|