@effect/language-service 0.83.1 → 0.84.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -2
- package/cli.js +587 -61
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +388 -55
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +388 -55
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/schema.json +110 -2
- package/transform.js +388 -55
- package/transform.js.map +1 -1
|
@@ -3126,6 +3126,25 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
3126
3126
|
return typeChecker.getTypeAtLocation(node);
|
|
3127
3127
|
}
|
|
3128
3128
|
}
|
|
3129
|
+
function resolveToGlobalSymbol(symbol3) {
|
|
3130
|
+
if (symbol3.flags & ts.SymbolFlags.Alias) {
|
|
3131
|
+
symbol3 = typeChecker.getAliasedSymbol(symbol3);
|
|
3132
|
+
}
|
|
3133
|
+
let depth = 0;
|
|
3134
|
+
while (depth < 2 && symbol3.valueDeclaration && ts.isVariableDeclaration(symbol3.valueDeclaration)) {
|
|
3135
|
+
const initializer = symbol3.valueDeclaration.initializer;
|
|
3136
|
+
if (!initializer) break;
|
|
3137
|
+
let nextSymbol = typeChecker.getSymbolAtLocation(initializer);
|
|
3138
|
+
if (!nextSymbol) break;
|
|
3139
|
+
if (nextSymbol.flags & ts.SymbolFlags.Alias) {
|
|
3140
|
+
nextSymbol = typeChecker.getAliasedSymbol(nextSymbol);
|
|
3141
|
+
}
|
|
3142
|
+
if (nextSymbol === symbol3) break;
|
|
3143
|
+
symbol3 = nextSymbol;
|
|
3144
|
+
depth++;
|
|
3145
|
+
}
|
|
3146
|
+
return symbol3;
|
|
3147
|
+
}
|
|
3129
3148
|
return {
|
|
3130
3149
|
isUnion,
|
|
3131
3150
|
isReadonlyArrayType,
|
|
@@ -3139,7 +3158,8 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
3139
3158
|
expectedAndRealType,
|
|
3140
3159
|
typeToSimplifiedTypeNode,
|
|
3141
3160
|
isGlobalErrorType,
|
|
3142
|
-
getTypeAtLocation
|
|
3161
|
+
getTypeAtLocation,
|
|
3162
|
+
resolveToGlobalSymbol
|
|
3143
3163
|
};
|
|
3144
3164
|
}
|
|
3145
3165
|
|
|
@@ -3827,7 +3847,11 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3827
3847
|
}
|
|
3828
3848
|
currentParent = nodeToCheck.parent;
|
|
3829
3849
|
}
|
|
3830
|
-
return {
|
|
3850
|
+
return {
|
|
3851
|
+
inEffect: effectGenResult !== void 0 && effectGenResult.body.statements.length > 0 && scopeNode === effectGenResult.generatorFunction,
|
|
3852
|
+
scopeNode,
|
|
3853
|
+
effectGen: effectGenResult
|
|
3854
|
+
};
|
|
3831
3855
|
});
|
|
3832
3856
|
const effectFn = cachedBy(
|
|
3833
3857
|
function(node) {
|
|
@@ -5913,12 +5937,14 @@ var getParameterName = (typescript, name) => {
|
|
|
5913
5937
|
}
|
|
5914
5938
|
return "parameter";
|
|
5915
5939
|
};
|
|
5916
|
-
var hasOuterContextualFunctionType = (typescript, typeChecker, node) => {
|
|
5940
|
+
var hasOuterContextualFunctionType = (typescript, typeChecker, typeCheckerUtils, node) => {
|
|
5917
5941
|
const contextualType = typeChecker.getContextualType(node);
|
|
5918
5942
|
if (!contextualType) {
|
|
5919
5943
|
return false;
|
|
5920
5944
|
}
|
|
5921
|
-
return
|
|
5945
|
+
return typeCheckerUtils.unrollUnionMembers(contextualType).some(
|
|
5946
|
+
(type) => typeChecker.getSignaturesOfType(type, typescript.SignatureKind.Call).length > 0
|
|
5947
|
+
);
|
|
5922
5948
|
};
|
|
5923
5949
|
var effectFnImplicitAny = createDiagnostic({
|
|
5924
5950
|
name: "effectFnImplicitAny",
|
|
@@ -5932,6 +5958,7 @@ var effectFnImplicitAny = createDiagnostic({
|
|
|
5932
5958
|
const ts = yield* service(TypeScriptApi);
|
|
5933
5959
|
const program = yield* service(TypeScriptProgram);
|
|
5934
5960
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
5961
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
5935
5962
|
const typeParser = yield* service(TypeParser);
|
|
5936
5963
|
const noImplicitAny = program.getCompilerOptions().noImplicitAny ?? program.getCompilerOptions().strict ?? false;
|
|
5937
5964
|
if (!noImplicitAny) {
|
|
@@ -5971,7 +5998,7 @@ var effectFnImplicitAny = createDiagnostic({
|
|
|
5971
5998
|
),
|
|
5972
5999
|
orUndefined
|
|
5973
6000
|
);
|
|
5974
|
-
if (!parsed || hasOuterContextualFunctionType(ts, typeChecker, parsed.call)) {
|
|
6001
|
+
if (!parsed || hasOuterContextualFunctionType(ts, typeChecker, typeCheckerUtils, parsed.call)) {
|
|
5975
6002
|
continue;
|
|
5976
6003
|
}
|
|
5977
6004
|
for (const parameter of parsed.fn.parameters) {
|
|
@@ -7022,6 +7049,128 @@ var genericEffectServices = createDiagnostic({
|
|
|
7022
7049
|
})
|
|
7023
7050
|
});
|
|
7024
7051
|
|
|
7052
|
+
// src/diagnostics/globalConsoleInEffect.ts
|
|
7053
|
+
var consoleMethodAlternatives = {
|
|
7054
|
+
"log": "Effect.log or Logger",
|
|
7055
|
+
"warn": "Effect.logWarning or Logger",
|
|
7056
|
+
"error": "Effect.logError or Logger",
|
|
7057
|
+
"info": "Effect.logInfo or Logger",
|
|
7058
|
+
"debug": "Effect.logDebug or Logger",
|
|
7059
|
+
"trace": "Effect.logTrace or Logger"
|
|
7060
|
+
};
|
|
7061
|
+
var makeGlobalConsoleApply = (checkInEffect) => fn(`globalConsole${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
7062
|
+
const ts = yield* service(TypeScriptApi);
|
|
7063
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
7064
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7065
|
+
const typeParser = yield* service(TypeParser);
|
|
7066
|
+
const consoleSymbol = typeChecker.resolveName("console", void 0, ts.SymbolFlags.Value, false);
|
|
7067
|
+
if (!consoleSymbol) return;
|
|
7068
|
+
const nodeToVisit = [];
|
|
7069
|
+
const appendNodeToVisit = (node) => {
|
|
7070
|
+
nodeToVisit.push(node);
|
|
7071
|
+
return void 0;
|
|
7072
|
+
};
|
|
7073
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
7074
|
+
while (nodeToVisit.length > 0) {
|
|
7075
|
+
const node = nodeToVisit.shift();
|
|
7076
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
7077
|
+
if (!ts.isCallExpression(node) || !ts.isPropertyAccessExpression(node.expression)) continue;
|
|
7078
|
+
const method = ts.idText(node.expression.name);
|
|
7079
|
+
const alternative = consoleMethodAlternatives[method];
|
|
7080
|
+
if (!alternative) continue;
|
|
7081
|
+
const symbol3 = typeChecker.getSymbolAtLocation(node.expression.expression);
|
|
7082
|
+
if (!symbol3) continue;
|
|
7083
|
+
if (typeCheckerUtils.resolveToGlobalSymbol(symbol3) !== consoleSymbol) continue;
|
|
7084
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
7085
|
+
if (inEffect !== checkInEffect) continue;
|
|
7086
|
+
report({
|
|
7087
|
+
location: node,
|
|
7088
|
+
messageText: checkInEffect ? `Prefer using ${alternative} instead of console.${method} inside Effect generators.` : `Prefer using ${alternative} instead of console.${method}.`,
|
|
7089
|
+
fixes: []
|
|
7090
|
+
});
|
|
7091
|
+
}
|
|
7092
|
+
});
|
|
7093
|
+
var globalConsoleInEffect = createDiagnostic({
|
|
7094
|
+
name: "globalConsoleInEffect",
|
|
7095
|
+
code: 56,
|
|
7096
|
+
description: "Warns when using console methods inside Effect generators instead of Effect.log/Logger",
|
|
7097
|
+
group: "effectNative",
|
|
7098
|
+
severity: "off",
|
|
7099
|
+
fixable: false,
|
|
7100
|
+
supportedEffect: ["v3", "v4"],
|
|
7101
|
+
apply: makeGlobalConsoleApply(true)
|
|
7102
|
+
});
|
|
7103
|
+
|
|
7104
|
+
// src/diagnostics/globalConsole.ts
|
|
7105
|
+
var globalConsole = createDiagnostic({
|
|
7106
|
+
name: "globalConsole",
|
|
7107
|
+
code: 60,
|
|
7108
|
+
description: "Warns when using console methods outside Effect generators instead of Effect.log/Logger",
|
|
7109
|
+
group: "effectNative",
|
|
7110
|
+
severity: "off",
|
|
7111
|
+
fixable: false,
|
|
7112
|
+
supportedEffect: ["v3", "v4"],
|
|
7113
|
+
apply: makeGlobalConsoleApply(false)
|
|
7114
|
+
});
|
|
7115
|
+
|
|
7116
|
+
// src/diagnostics/globalDateInEffect.ts
|
|
7117
|
+
var makeGlobalDateApply = (checkInEffect) => fn(`globalDate${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
7118
|
+
const ts = yield* service(TypeScriptApi);
|
|
7119
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
7120
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7121
|
+
const typeParser = yield* service(TypeParser);
|
|
7122
|
+
const dateSymbol = typeChecker.resolveName("Date", void 0, ts.SymbolFlags.Value, false);
|
|
7123
|
+
if (!dateSymbol) return;
|
|
7124
|
+
const nodeToVisit = [];
|
|
7125
|
+
const appendNodeToVisit = (node) => {
|
|
7126
|
+
nodeToVisit.push(node);
|
|
7127
|
+
return void 0;
|
|
7128
|
+
};
|
|
7129
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
7130
|
+
while (nodeToVisit.length > 0) {
|
|
7131
|
+
const node = nodeToVisit.shift();
|
|
7132
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
7133
|
+
let messageText;
|
|
7134
|
+
let objectNode;
|
|
7135
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.idText(node.expression.name) === "now") {
|
|
7136
|
+
objectNode = node.expression.expression;
|
|
7137
|
+
messageText = checkInEffect ? "Prefer using Clock or DateTime from Effect instead of Date.now() inside Effect generators." : "Prefer using Clock or DateTime from Effect instead of Date.now().";
|
|
7138
|
+
} else if (ts.isNewExpression(node)) {
|
|
7139
|
+
objectNode = node.expression;
|
|
7140
|
+
messageText = checkInEffect ? "Prefer using DateTime from Effect instead of new Date() inside Effect generators." : "Prefer using DateTime from Effect instead of new Date().";
|
|
7141
|
+
}
|
|
7142
|
+
if (!messageText || !objectNode) continue;
|
|
7143
|
+
const symbol3 = typeChecker.getSymbolAtLocation(objectNode);
|
|
7144
|
+
if (!symbol3) continue;
|
|
7145
|
+
if (typeCheckerUtils.resolveToGlobalSymbol(symbol3) !== dateSymbol) continue;
|
|
7146
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
7147
|
+
if (inEffect !== checkInEffect) continue;
|
|
7148
|
+
report({ location: node, messageText, fixes: [] });
|
|
7149
|
+
}
|
|
7150
|
+
});
|
|
7151
|
+
var globalDateInEffect = createDiagnostic({
|
|
7152
|
+
name: "globalDateInEffect",
|
|
7153
|
+
code: 55,
|
|
7154
|
+
description: "Warns when using Date.now() or new Date() inside Effect generators instead of Clock/DateTime",
|
|
7155
|
+
group: "effectNative",
|
|
7156
|
+
severity: "off",
|
|
7157
|
+
fixable: false,
|
|
7158
|
+
supportedEffect: ["v3", "v4"],
|
|
7159
|
+
apply: makeGlobalDateApply(true)
|
|
7160
|
+
});
|
|
7161
|
+
|
|
7162
|
+
// src/diagnostics/globalDate.ts
|
|
7163
|
+
var globalDate = createDiagnostic({
|
|
7164
|
+
name: "globalDate",
|
|
7165
|
+
code: 59,
|
|
7166
|
+
description: "Warns when using Date.now() or new Date() outside Effect generators instead of Clock/DateTime",
|
|
7167
|
+
group: "effectNative",
|
|
7168
|
+
severity: "off",
|
|
7169
|
+
fixable: false,
|
|
7170
|
+
supportedEffect: ["v3", "v4"],
|
|
7171
|
+
apply: makeGlobalDateApply(false)
|
|
7172
|
+
});
|
|
7173
|
+
|
|
7025
7174
|
// src/diagnostics/globalErrorInEffectCatch.ts
|
|
7026
7175
|
var globalErrorInEffectCatch = createDiagnostic({
|
|
7027
7176
|
name: "globalErrorInEffectCatch",
|
|
@@ -7141,46 +7290,186 @@ var globalErrorInEffectFailure = createDiagnostic({
|
|
|
7141
7290
|
})
|
|
7142
7291
|
});
|
|
7143
7292
|
|
|
7293
|
+
// src/diagnostics/globalFetchInEffect.ts
|
|
7294
|
+
var makeGlobalFetchApply = (checkInEffect) => fn(`globalFetch${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
7295
|
+
const ts = yield* service(TypeScriptApi);
|
|
7296
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
7297
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7298
|
+
const typeParser = yield* service(TypeParser);
|
|
7299
|
+
const fetchSymbol = typeChecker.resolveName("fetch", void 0, ts.SymbolFlags.Value, false);
|
|
7300
|
+
if (!fetchSymbol) return;
|
|
7301
|
+
const effectVersion = typeParser.supportedEffect();
|
|
7302
|
+
const packageName = effectVersion === "v3" ? "@effect/platform" : "effect/unstable/http";
|
|
7303
|
+
const messageText = checkInEffect ? `Prefer using HttpClient from ${packageName} instead of the global 'fetch' function inside Effect generators.` : `Prefer using HttpClient from ${packageName} instead of the global 'fetch' function.`;
|
|
7304
|
+
const nodeToVisit = [];
|
|
7305
|
+
const appendNodeToVisit = (node) => {
|
|
7306
|
+
nodeToVisit.push(node);
|
|
7307
|
+
return void 0;
|
|
7308
|
+
};
|
|
7309
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
7310
|
+
while (nodeToVisit.length > 0) {
|
|
7311
|
+
const node = nodeToVisit.shift();
|
|
7312
|
+
if (ts.isCallExpression(node)) {
|
|
7313
|
+
const symbol3 = typeChecker.getSymbolAtLocation(node.expression);
|
|
7314
|
+
if (symbol3 && typeCheckerUtils.resolveToGlobalSymbol(symbol3) === fetchSymbol) {
|
|
7315
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
7316
|
+
if (inEffect === checkInEffect) {
|
|
7317
|
+
report({
|
|
7318
|
+
location: node.expression,
|
|
7319
|
+
messageText,
|
|
7320
|
+
fixes: []
|
|
7321
|
+
});
|
|
7322
|
+
}
|
|
7323
|
+
}
|
|
7324
|
+
}
|
|
7325
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
7326
|
+
}
|
|
7327
|
+
});
|
|
7328
|
+
var globalFetchInEffect = createDiagnostic({
|
|
7329
|
+
name: "globalFetchInEffect",
|
|
7330
|
+
code: 63,
|
|
7331
|
+
description: "Warns when using the global fetch function inside Effect generators instead of the Effect HTTP client",
|
|
7332
|
+
group: "effectNative",
|
|
7333
|
+
severity: "off",
|
|
7334
|
+
fixable: false,
|
|
7335
|
+
supportedEffect: ["v3", "v4"],
|
|
7336
|
+
apply: makeGlobalFetchApply(true)
|
|
7337
|
+
});
|
|
7338
|
+
|
|
7144
7339
|
// src/diagnostics/globalFetch.ts
|
|
7145
7340
|
var globalFetch = createDiagnostic({
|
|
7146
7341
|
name: "globalFetch",
|
|
7147
7342
|
code: 53,
|
|
7148
|
-
description: "Warns when using the global fetch function instead of the Effect HTTP client",
|
|
7343
|
+
description: "Warns when using the global fetch function outside Effect generators instead of the Effect HTTP client",
|
|
7149
7344
|
group: "effectNative",
|
|
7150
7345
|
severity: "off",
|
|
7151
7346
|
fixable: false,
|
|
7152
7347
|
supportedEffect: ["v3", "v4"],
|
|
7153
|
-
apply:
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7348
|
+
apply: makeGlobalFetchApply(false)
|
|
7349
|
+
});
|
|
7350
|
+
|
|
7351
|
+
// src/diagnostics/globalRandomInEffect.ts
|
|
7352
|
+
var makeGlobalRandomApply = (checkInEffect) => fn(`globalRandom${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
7353
|
+
const ts = yield* service(TypeScriptApi);
|
|
7354
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
7355
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7356
|
+
const typeParser = yield* service(TypeParser);
|
|
7357
|
+
const mathSymbol = typeChecker.resolveName("Math", void 0, ts.SymbolFlags.Value, false);
|
|
7358
|
+
if (!mathSymbol) return;
|
|
7359
|
+
const nodeToVisit = [];
|
|
7360
|
+
const appendNodeToVisit = (node) => {
|
|
7361
|
+
nodeToVisit.push(node);
|
|
7362
|
+
return void 0;
|
|
7363
|
+
};
|
|
7364
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
7365
|
+
while (nodeToVisit.length > 0) {
|
|
7366
|
+
const node = nodeToVisit.shift();
|
|
7367
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
7368
|
+
if (!ts.isCallExpression(node) || !ts.isPropertyAccessExpression(node.expression) || ts.idText(node.expression.name) !== "random") continue;
|
|
7369
|
+
const symbol3 = typeChecker.getSymbolAtLocation(node.expression.expression);
|
|
7370
|
+
if (!symbol3) continue;
|
|
7371
|
+
if (typeCheckerUtils.resolveToGlobalSymbol(symbol3) !== mathSymbol) continue;
|
|
7372
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
7373
|
+
if (inEffect !== checkInEffect) continue;
|
|
7374
|
+
report({
|
|
7375
|
+
location: node,
|
|
7376
|
+
messageText: checkInEffect ? "Prefer using the Random service from Effect instead of Math.random() inside Effect generators." : "Prefer using the Random service from Effect instead of Math.random().",
|
|
7377
|
+
fixes: []
|
|
7378
|
+
});
|
|
7379
|
+
}
|
|
7380
|
+
});
|
|
7381
|
+
var globalRandomInEffect = createDiagnostic({
|
|
7382
|
+
name: "globalRandomInEffect",
|
|
7383
|
+
code: 57,
|
|
7384
|
+
description: "Warns when using Math.random() inside Effect generators instead of the Random service",
|
|
7385
|
+
group: "effectNative",
|
|
7386
|
+
severity: "off",
|
|
7387
|
+
fixable: false,
|
|
7388
|
+
supportedEffect: ["v3", "v4"],
|
|
7389
|
+
apply: makeGlobalRandomApply(true)
|
|
7390
|
+
});
|
|
7391
|
+
|
|
7392
|
+
// src/diagnostics/globalRandom.ts
|
|
7393
|
+
var globalRandom = createDiagnostic({
|
|
7394
|
+
name: "globalRandom",
|
|
7395
|
+
code: 61,
|
|
7396
|
+
description: "Warns when using Math.random() outside Effect generators instead of the Random service",
|
|
7397
|
+
group: "effectNative",
|
|
7398
|
+
severity: "off",
|
|
7399
|
+
fixable: false,
|
|
7400
|
+
supportedEffect: ["v3", "v4"],
|
|
7401
|
+
apply: makeGlobalRandomApply(false)
|
|
7402
|
+
});
|
|
7403
|
+
|
|
7404
|
+
// src/diagnostics/globalTimersInEffect.ts
|
|
7405
|
+
var timerAlternatives = {
|
|
7406
|
+
"setTimeout": {
|
|
7407
|
+
inEffect: "Prefer using Effect.sleep or Schedule from Effect instead of setTimeout inside Effect generators.",
|
|
7408
|
+
outsideEffect: "Prefer using Effect.sleep or Schedule from Effect instead of setTimeout."
|
|
7409
|
+
},
|
|
7410
|
+
"setInterval": {
|
|
7411
|
+
inEffect: "Prefer using Schedule or Effect.repeat from Effect instead of setInterval inside Effect generators.",
|
|
7412
|
+
outsideEffect: "Prefer using Schedule or Effect.repeat from Effect instead of setInterval."
|
|
7413
|
+
}
|
|
7414
|
+
};
|
|
7415
|
+
var makeGlobalTimersApply = (checkInEffect) => fn(`globalTimers${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
7416
|
+
const ts = yield* service(TypeScriptApi);
|
|
7417
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
7418
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7419
|
+
const typeParser = yield* service(TypeParser);
|
|
7420
|
+
const globalSymbols = /* @__PURE__ */ new Map();
|
|
7421
|
+
for (const name of Object.keys(timerAlternatives)) {
|
|
7422
|
+
const symbol3 = typeChecker.resolveName(name, void 0, ts.SymbolFlags.Value, false);
|
|
7423
|
+
if (symbol3) globalSymbols.set(name, symbol3);
|
|
7424
|
+
}
|
|
7425
|
+
if (globalSymbols.size === 0) return;
|
|
7426
|
+
const nodeToVisit = [];
|
|
7427
|
+
const appendNodeToVisit = (node) => {
|
|
7428
|
+
nodeToVisit.push(node);
|
|
7429
|
+
return void 0;
|
|
7430
|
+
};
|
|
7431
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
7432
|
+
while (nodeToVisit.length > 0) {
|
|
7433
|
+
const node = nodeToVisit.shift();
|
|
7434
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
7435
|
+
if (!ts.isCallExpression(node)) continue;
|
|
7436
|
+
const symbol3 = typeChecker.getSymbolAtLocation(node.expression);
|
|
7437
|
+
if (!symbol3) continue;
|
|
7438
|
+
const resolvedSymbol = typeCheckerUtils.resolveToGlobalSymbol(symbol3);
|
|
7439
|
+
let messageText;
|
|
7440
|
+
for (const [name, symbol4] of globalSymbols) {
|
|
7441
|
+
if (resolvedSymbol === symbol4) {
|
|
7442
|
+
messageText = checkInEffect ? timerAlternatives[name].inEffect : timerAlternatives[name].outsideEffect;
|
|
7443
|
+
break;
|
|
7180
7444
|
}
|
|
7181
|
-
ts.forEachChild(node, appendNodeToVisit);
|
|
7182
7445
|
}
|
|
7183
|
-
|
|
7446
|
+
if (!messageText) continue;
|
|
7447
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
7448
|
+
if (inEffect !== checkInEffect) continue;
|
|
7449
|
+
report({ location: node, messageText, fixes: [] });
|
|
7450
|
+
}
|
|
7451
|
+
});
|
|
7452
|
+
var globalTimersInEffect = createDiagnostic({
|
|
7453
|
+
name: "globalTimersInEffect",
|
|
7454
|
+
code: 58,
|
|
7455
|
+
description: "Warns when using setTimeout/setInterval inside Effect generators instead of Effect.sleep/Schedule",
|
|
7456
|
+
group: "effectNative",
|
|
7457
|
+
severity: "off",
|
|
7458
|
+
fixable: false,
|
|
7459
|
+
supportedEffect: ["v3", "v4"],
|
|
7460
|
+
apply: makeGlobalTimersApply(true)
|
|
7461
|
+
});
|
|
7462
|
+
|
|
7463
|
+
// src/diagnostics/globalTimers.ts
|
|
7464
|
+
var globalTimers = createDiagnostic({
|
|
7465
|
+
name: "globalTimers",
|
|
7466
|
+
code: 62,
|
|
7467
|
+
description: "Warns when using setTimeout/setInterval outside Effect generators instead of Effect.sleep/Schedule",
|
|
7468
|
+
group: "effectNative",
|
|
7469
|
+
severity: "off",
|
|
7470
|
+
fixable: false,
|
|
7471
|
+
supportedEffect: ["v3", "v4"],
|
|
7472
|
+
apply: makeGlobalTimersApply(false)
|
|
7184
7473
|
});
|
|
7185
7474
|
|
|
7186
7475
|
// src/diagnostics/importFromBarrel.ts
|
|
@@ -8245,8 +8534,8 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
8245
8534
|
if (!type) continue;
|
|
8246
8535
|
const maybeEffect = yield* option(typeParser.effectYieldableType(type, unwrapped.expression));
|
|
8247
8536
|
if (!(isSome2(maybeEffect) && maybeEffect.value.A.flags & ts.TypeFlags.Never)) continue;
|
|
8248
|
-
const {
|
|
8249
|
-
if (!
|
|
8537
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
8538
|
+
if (!inEffect) continue;
|
|
8250
8539
|
const fix = [{
|
|
8251
8540
|
fixName: "missingReturnYieldStar_fix",
|
|
8252
8541
|
description: "Add return statement",
|
|
@@ -10709,11 +10998,8 @@ var preferSchemaOverJson = createDiagnostic({
|
|
|
10709
10998
|
});
|
|
10710
10999
|
const jsonMethodInEffectGen = fn("preferSchemaOverJson.jsonMethodInEffectGen")(
|
|
10711
11000
|
function* (jsonCall) {
|
|
10712
|
-
const {
|
|
10713
|
-
if (!
|
|
10714
|
-
return yield* TypeParserIssue.issue;
|
|
10715
|
-
}
|
|
10716
|
-
if (scopeNode && scopeNode !== effectGen.generatorFunction) {
|
|
11001
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(jsonCall);
|
|
11002
|
+
if (!inEffect) {
|
|
10717
11003
|
return yield* TypeParserIssue.issue;
|
|
10718
11004
|
}
|
|
10719
11005
|
return jsonCall;
|
|
@@ -10876,16 +11162,16 @@ Nested Effect-able types may be intended if you plan to later manually flatten o
|
|
|
10876
11162
|
var runEffectInsideEffect = createDiagnostic({
|
|
10877
11163
|
name: "runEffectInsideEffect",
|
|
10878
11164
|
code: 32,
|
|
10879
|
-
description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
|
|
11165
|
+
description: "Suggests using Runtime or Effect.run*With methods instead of Effect.run* inside Effect contexts",
|
|
10880
11166
|
group: "antipattern",
|
|
10881
11167
|
severity: "suggestion",
|
|
10882
11168
|
fixable: true,
|
|
10883
|
-
supportedEffect: ["v3"],
|
|
11169
|
+
supportedEffect: ["v3", "v4"],
|
|
10884
11170
|
apply: fn("runEffectInsideEffect.apply")(function* (sourceFile, report) {
|
|
10885
11171
|
const ts = yield* service(TypeScriptApi);
|
|
10886
11172
|
const typeParser = yield* service(TypeParser);
|
|
10887
11173
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
10888
|
-
|
|
11174
|
+
const supportedEffect = typeParser.supportedEffect();
|
|
10889
11175
|
const parseEffectMethod = (node, methodName) => pipe(
|
|
10890
11176
|
typeParser.isNodeReferenceToEffectModuleApi(methodName)(node),
|
|
10891
11177
|
map4(() => ({ node, methodName }))
|
|
@@ -10918,9 +11204,10 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
10918
11204
|
if (scopeNode && scopeNode !== effectGen.generatorFunction) {
|
|
10919
11205
|
const fixAddRuntime = gen(function* () {
|
|
10920
11206
|
const changeTracker = yield* service(ChangeTracker);
|
|
10921
|
-
const runtimeModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Runtime") || "Runtime";
|
|
10922
11207
|
const effectModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Effect") || "Effect";
|
|
11208
|
+
const runtimeModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Runtime") || "Runtime";
|
|
10923
11209
|
let runtimeIdentifier = void 0;
|
|
11210
|
+
let servicesIdentifier = void 0;
|
|
10924
11211
|
for (const statement of effectGen.generatorFunction.body.statements) {
|
|
10925
11212
|
if (ts.isVariableStatement(statement) && statement.declarationList.declarations.length === 1) {
|
|
10926
11213
|
const declaration = statement.declarationList.declarations[0];
|
|
@@ -10934,11 +11221,46 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
10934
11221
|
if (isSome2(maybeEffectRuntime) && ts.isIdentifier(declaration.name)) {
|
|
10935
11222
|
runtimeIdentifier = ts.idText(declaration.name);
|
|
10936
11223
|
}
|
|
11224
|
+
const maybeEffectServices = yield* pipe(
|
|
11225
|
+
typeParser.isNodeReferenceToEffectModuleApi("services")(yieldedExpression.expression),
|
|
11226
|
+
option
|
|
11227
|
+
);
|
|
11228
|
+
if (isSome2(maybeEffectServices) && ts.isIdentifier(declaration.name)) {
|
|
11229
|
+
servicesIdentifier = ts.idText(declaration.name);
|
|
11230
|
+
}
|
|
10937
11231
|
}
|
|
10938
11232
|
}
|
|
10939
11233
|
}
|
|
10940
11234
|
}
|
|
10941
|
-
if (!
|
|
11235
|
+
if (supportedEffect === "v4" && !servicesIdentifier) {
|
|
11236
|
+
changeTracker.insertNodeAt(
|
|
11237
|
+
sourceFile,
|
|
11238
|
+
effectGen.body.statements[0].pos,
|
|
11239
|
+
ts.factory.createVariableStatement(
|
|
11240
|
+
void 0,
|
|
11241
|
+
ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration(
|
|
11242
|
+
"effectServices",
|
|
11243
|
+
void 0,
|
|
11244
|
+
void 0,
|
|
11245
|
+
ts.factory.createYieldExpression(
|
|
11246
|
+
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
11247
|
+
ts.factory.createCallExpression(
|
|
11248
|
+
ts.factory.createPropertyAccessExpression(
|
|
11249
|
+
ts.factory.createIdentifier(effectModuleIdentifier),
|
|
11250
|
+
"services"
|
|
11251
|
+
),
|
|
11252
|
+
[ts.factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)],
|
|
11253
|
+
[]
|
|
11254
|
+
)
|
|
11255
|
+
)
|
|
11256
|
+
)], ts.NodeFlags.Const)
|
|
11257
|
+
),
|
|
11258
|
+
{
|
|
11259
|
+
prefix: "\n",
|
|
11260
|
+
suffix: "\n"
|
|
11261
|
+
}
|
|
11262
|
+
);
|
|
11263
|
+
} else if (supportedEffect === "v3" && !runtimeIdentifier) {
|
|
10942
11264
|
changeTracker.insertNodeAt(
|
|
10943
11265
|
sourceFile,
|
|
10944
11266
|
effectGen.body.statements[0].pos,
|
|
@@ -10974,16 +11296,19 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
10974
11296
|
changeTracker.insertText(
|
|
10975
11297
|
sourceFile,
|
|
10976
11298
|
node.arguments[0].pos,
|
|
10977
|
-
`${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
|
|
11299
|
+
supportedEffect === "v4" ? `${effectModuleIdentifier}.${isEffectRunCall.value.methodName}With(${servicesIdentifier || "effectServices"})(` : `${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
|
|
10978
11300
|
);
|
|
10979
11301
|
});
|
|
11302
|
+
const v4MethodName = `${isEffectRunCall.value.methodName}With`;
|
|
11303
|
+
const messageText = supportedEffect === "v4" ? `Using ${nodeText} inside an Effect is not recommended. The same services should generally be used instead to run child effects.
|
|
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.`;
|
|
10980
11306
|
report({
|
|
10981
11307
|
location: node.expression,
|
|
10982
|
-
messageText
|
|
10983
|
-
Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`,
|
|
11308
|
+
messageText,
|
|
10984
11309
|
fixes: [{
|
|
10985
11310
|
fixName: "runEffectInsideEffect_fix",
|
|
10986
|
-
description: "Use a runtime to run the Effect",
|
|
11311
|
+
description: supportedEffect === "v4" ? "Use the current services to run the Effect" : "Use a runtime to run the Effect",
|
|
10987
11312
|
apply: fixAddRuntime
|
|
10988
11313
|
}]
|
|
10989
11314
|
});
|
|
@@ -11129,9 +11454,8 @@ var schemaSyncInEffect = createDiagnostic({
|
|
|
11129
11454
|
option
|
|
11130
11455
|
);
|
|
11131
11456
|
if (isNone2(isSchemaSyncCall)) continue;
|
|
11132
|
-
const {
|
|
11133
|
-
if (!
|
|
11134
|
-
if (scopeNode && scopeNode !== effectGen.generatorFunction) continue;
|
|
11457
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
11458
|
+
if (!inEffect) continue;
|
|
11135
11459
|
const nodeText = sourceFile.text.substring(
|
|
11136
11460
|
ts.getTokenPosOfNode(node.expression, sourceFile),
|
|
11137
11461
|
node.expression.end
|
|
@@ -11973,6 +12297,7 @@ var diagnostics = [
|
|
|
11973
12297
|
unnecessaryPipe,
|
|
11974
12298
|
genericEffectServices,
|
|
11975
12299
|
globalFetch,
|
|
12300
|
+
globalFetchInEffect,
|
|
11976
12301
|
returnEffectInGen,
|
|
11977
12302
|
tryCatchInEffectGen,
|
|
11978
12303
|
importFromBarrel,
|
|
@@ -12004,7 +12329,15 @@ var diagnostics = [
|
|
|
12004
12329
|
preferSchemaOverJson,
|
|
12005
12330
|
extendsNativeError,
|
|
12006
12331
|
serviceNotAsClass,
|
|
12007
|
-
nodeBuiltinImport
|
|
12332
|
+
nodeBuiltinImport,
|
|
12333
|
+
globalDate,
|
|
12334
|
+
globalDateInEffect,
|
|
12335
|
+
globalConsole,
|
|
12336
|
+
globalConsoleInEffect,
|
|
12337
|
+
globalRandom,
|
|
12338
|
+
globalRandomInEffect,
|
|
12339
|
+
globalTimers,
|
|
12340
|
+
globalTimersInEffect
|
|
12008
12341
|
];
|
|
12009
12342
|
|
|
12010
12343
|
// src/effect-lsp-patch-utils.ts
|