@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
package/transform.js
CHANGED
|
@@ -3122,6 +3122,25 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
3122
3122
|
return typeChecker.getTypeAtLocation(node);
|
|
3123
3123
|
}
|
|
3124
3124
|
}
|
|
3125
|
+
function resolveToGlobalSymbol(symbol3) {
|
|
3126
|
+
if (symbol3.flags & ts.SymbolFlags.Alias) {
|
|
3127
|
+
symbol3 = typeChecker.getAliasedSymbol(symbol3);
|
|
3128
|
+
}
|
|
3129
|
+
let depth = 0;
|
|
3130
|
+
while (depth < 2 && symbol3.valueDeclaration && ts.isVariableDeclaration(symbol3.valueDeclaration)) {
|
|
3131
|
+
const initializer = symbol3.valueDeclaration.initializer;
|
|
3132
|
+
if (!initializer) break;
|
|
3133
|
+
let nextSymbol = typeChecker.getSymbolAtLocation(initializer);
|
|
3134
|
+
if (!nextSymbol) break;
|
|
3135
|
+
if (nextSymbol.flags & ts.SymbolFlags.Alias) {
|
|
3136
|
+
nextSymbol = typeChecker.getAliasedSymbol(nextSymbol);
|
|
3137
|
+
}
|
|
3138
|
+
if (nextSymbol === symbol3) break;
|
|
3139
|
+
symbol3 = nextSymbol;
|
|
3140
|
+
depth++;
|
|
3141
|
+
}
|
|
3142
|
+
return symbol3;
|
|
3143
|
+
}
|
|
3125
3144
|
return {
|
|
3126
3145
|
isUnion,
|
|
3127
3146
|
isReadonlyArrayType,
|
|
@@ -3135,7 +3154,8 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
3135
3154
|
expectedAndRealType,
|
|
3136
3155
|
typeToSimplifiedTypeNode,
|
|
3137
3156
|
isGlobalErrorType,
|
|
3138
|
-
getTypeAtLocation
|
|
3157
|
+
getTypeAtLocation,
|
|
3158
|
+
resolveToGlobalSymbol
|
|
3139
3159
|
};
|
|
3140
3160
|
}
|
|
3141
3161
|
|
|
@@ -3823,7 +3843,11 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3823
3843
|
}
|
|
3824
3844
|
currentParent = nodeToCheck.parent;
|
|
3825
3845
|
}
|
|
3826
|
-
return {
|
|
3846
|
+
return {
|
|
3847
|
+
inEffect: effectGenResult !== void 0 && effectGenResult.body.statements.length > 0 && scopeNode === effectGenResult.generatorFunction,
|
|
3848
|
+
scopeNode,
|
|
3849
|
+
effectGen: effectGenResult
|
|
3850
|
+
};
|
|
3827
3851
|
});
|
|
3828
3852
|
const effectFn = cachedBy(
|
|
3829
3853
|
function(node) {
|
|
@@ -5909,12 +5933,14 @@ var getParameterName = (typescript, name) => {
|
|
|
5909
5933
|
}
|
|
5910
5934
|
return "parameter";
|
|
5911
5935
|
};
|
|
5912
|
-
var hasOuterContextualFunctionType = (typescript, typeChecker, node) => {
|
|
5936
|
+
var hasOuterContextualFunctionType = (typescript, typeChecker, typeCheckerUtils, node) => {
|
|
5913
5937
|
const contextualType = typeChecker.getContextualType(node);
|
|
5914
5938
|
if (!contextualType) {
|
|
5915
5939
|
return false;
|
|
5916
5940
|
}
|
|
5917
|
-
return
|
|
5941
|
+
return typeCheckerUtils.unrollUnionMembers(contextualType).some(
|
|
5942
|
+
(type) => typeChecker.getSignaturesOfType(type, typescript.SignatureKind.Call).length > 0
|
|
5943
|
+
);
|
|
5918
5944
|
};
|
|
5919
5945
|
var effectFnImplicitAny = createDiagnostic({
|
|
5920
5946
|
name: "effectFnImplicitAny",
|
|
@@ -5928,6 +5954,7 @@ var effectFnImplicitAny = createDiagnostic({
|
|
|
5928
5954
|
const ts = yield* service(TypeScriptApi);
|
|
5929
5955
|
const program = yield* service(TypeScriptProgram);
|
|
5930
5956
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
5957
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
5931
5958
|
const typeParser = yield* service(TypeParser);
|
|
5932
5959
|
const noImplicitAny = program.getCompilerOptions().noImplicitAny ?? program.getCompilerOptions().strict ?? false;
|
|
5933
5960
|
if (!noImplicitAny) {
|
|
@@ -5967,7 +5994,7 @@ var effectFnImplicitAny = createDiagnostic({
|
|
|
5967
5994
|
),
|
|
5968
5995
|
orUndefined
|
|
5969
5996
|
);
|
|
5970
|
-
if (!parsed || hasOuterContextualFunctionType(ts, typeChecker, parsed.call)) {
|
|
5997
|
+
if (!parsed || hasOuterContextualFunctionType(ts, typeChecker, typeCheckerUtils, parsed.call)) {
|
|
5971
5998
|
continue;
|
|
5972
5999
|
}
|
|
5973
6000
|
for (const parameter of parsed.fn.parameters) {
|
|
@@ -7018,6 +7045,128 @@ var genericEffectServices = createDiagnostic({
|
|
|
7018
7045
|
})
|
|
7019
7046
|
});
|
|
7020
7047
|
|
|
7048
|
+
// src/diagnostics/globalConsoleInEffect.ts
|
|
7049
|
+
var consoleMethodAlternatives = {
|
|
7050
|
+
"log": "Effect.log or Logger",
|
|
7051
|
+
"warn": "Effect.logWarning or Logger",
|
|
7052
|
+
"error": "Effect.logError or Logger",
|
|
7053
|
+
"info": "Effect.logInfo or Logger",
|
|
7054
|
+
"debug": "Effect.logDebug or Logger",
|
|
7055
|
+
"trace": "Effect.logTrace or Logger"
|
|
7056
|
+
};
|
|
7057
|
+
var makeGlobalConsoleApply = (checkInEffect) => fn(`globalConsole${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
7058
|
+
const ts = yield* service(TypeScriptApi);
|
|
7059
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
7060
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7061
|
+
const typeParser = yield* service(TypeParser);
|
|
7062
|
+
const consoleSymbol = typeChecker.resolveName("console", void 0, ts.SymbolFlags.Value, false);
|
|
7063
|
+
if (!consoleSymbol) return;
|
|
7064
|
+
const nodeToVisit = [];
|
|
7065
|
+
const appendNodeToVisit = (node) => {
|
|
7066
|
+
nodeToVisit.push(node);
|
|
7067
|
+
return void 0;
|
|
7068
|
+
};
|
|
7069
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
7070
|
+
while (nodeToVisit.length > 0) {
|
|
7071
|
+
const node = nodeToVisit.shift();
|
|
7072
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
7073
|
+
if (!ts.isCallExpression(node) || !ts.isPropertyAccessExpression(node.expression)) continue;
|
|
7074
|
+
const method = ts.idText(node.expression.name);
|
|
7075
|
+
const alternative = consoleMethodAlternatives[method];
|
|
7076
|
+
if (!alternative) continue;
|
|
7077
|
+
const symbol3 = typeChecker.getSymbolAtLocation(node.expression.expression);
|
|
7078
|
+
if (!symbol3) continue;
|
|
7079
|
+
if (typeCheckerUtils.resolveToGlobalSymbol(symbol3) !== consoleSymbol) continue;
|
|
7080
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
7081
|
+
if (inEffect !== checkInEffect) continue;
|
|
7082
|
+
report({
|
|
7083
|
+
location: node,
|
|
7084
|
+
messageText: checkInEffect ? `Prefer using ${alternative} instead of console.${method} inside Effect generators.` : `Prefer using ${alternative} instead of console.${method}.`,
|
|
7085
|
+
fixes: []
|
|
7086
|
+
});
|
|
7087
|
+
}
|
|
7088
|
+
});
|
|
7089
|
+
var globalConsoleInEffect = createDiagnostic({
|
|
7090
|
+
name: "globalConsoleInEffect",
|
|
7091
|
+
code: 56,
|
|
7092
|
+
description: "Warns when using console methods inside Effect generators instead of Effect.log/Logger",
|
|
7093
|
+
group: "effectNative",
|
|
7094
|
+
severity: "off",
|
|
7095
|
+
fixable: false,
|
|
7096
|
+
supportedEffect: ["v3", "v4"],
|
|
7097
|
+
apply: makeGlobalConsoleApply(true)
|
|
7098
|
+
});
|
|
7099
|
+
|
|
7100
|
+
// src/diagnostics/globalConsole.ts
|
|
7101
|
+
var globalConsole = createDiagnostic({
|
|
7102
|
+
name: "globalConsole",
|
|
7103
|
+
code: 60,
|
|
7104
|
+
description: "Warns when using console methods outside Effect generators instead of Effect.log/Logger",
|
|
7105
|
+
group: "effectNative",
|
|
7106
|
+
severity: "off",
|
|
7107
|
+
fixable: false,
|
|
7108
|
+
supportedEffect: ["v3", "v4"],
|
|
7109
|
+
apply: makeGlobalConsoleApply(false)
|
|
7110
|
+
});
|
|
7111
|
+
|
|
7112
|
+
// src/diagnostics/globalDateInEffect.ts
|
|
7113
|
+
var makeGlobalDateApply = (checkInEffect) => fn(`globalDate${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
7114
|
+
const ts = yield* service(TypeScriptApi);
|
|
7115
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
7116
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7117
|
+
const typeParser = yield* service(TypeParser);
|
|
7118
|
+
const dateSymbol = typeChecker.resolveName("Date", void 0, ts.SymbolFlags.Value, false);
|
|
7119
|
+
if (!dateSymbol) return;
|
|
7120
|
+
const nodeToVisit = [];
|
|
7121
|
+
const appendNodeToVisit = (node) => {
|
|
7122
|
+
nodeToVisit.push(node);
|
|
7123
|
+
return void 0;
|
|
7124
|
+
};
|
|
7125
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
7126
|
+
while (nodeToVisit.length > 0) {
|
|
7127
|
+
const node = nodeToVisit.shift();
|
|
7128
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
7129
|
+
let messageText;
|
|
7130
|
+
let objectNode;
|
|
7131
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.idText(node.expression.name) === "now") {
|
|
7132
|
+
objectNode = node.expression.expression;
|
|
7133
|
+
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().";
|
|
7134
|
+
} else if (ts.isNewExpression(node)) {
|
|
7135
|
+
objectNode = node.expression;
|
|
7136
|
+
messageText = checkInEffect ? "Prefer using DateTime from Effect instead of new Date() inside Effect generators." : "Prefer using DateTime from Effect instead of new Date().";
|
|
7137
|
+
}
|
|
7138
|
+
if (!messageText || !objectNode) continue;
|
|
7139
|
+
const symbol3 = typeChecker.getSymbolAtLocation(objectNode);
|
|
7140
|
+
if (!symbol3) continue;
|
|
7141
|
+
if (typeCheckerUtils.resolveToGlobalSymbol(symbol3) !== dateSymbol) continue;
|
|
7142
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
7143
|
+
if (inEffect !== checkInEffect) continue;
|
|
7144
|
+
report({ location: node, messageText, fixes: [] });
|
|
7145
|
+
}
|
|
7146
|
+
});
|
|
7147
|
+
var globalDateInEffect = createDiagnostic({
|
|
7148
|
+
name: "globalDateInEffect",
|
|
7149
|
+
code: 55,
|
|
7150
|
+
description: "Warns when using Date.now() or new Date() inside Effect generators instead of Clock/DateTime",
|
|
7151
|
+
group: "effectNative",
|
|
7152
|
+
severity: "off",
|
|
7153
|
+
fixable: false,
|
|
7154
|
+
supportedEffect: ["v3", "v4"],
|
|
7155
|
+
apply: makeGlobalDateApply(true)
|
|
7156
|
+
});
|
|
7157
|
+
|
|
7158
|
+
// src/diagnostics/globalDate.ts
|
|
7159
|
+
var globalDate = createDiagnostic({
|
|
7160
|
+
name: "globalDate",
|
|
7161
|
+
code: 59,
|
|
7162
|
+
description: "Warns when using Date.now() or new Date() outside Effect generators instead of Clock/DateTime",
|
|
7163
|
+
group: "effectNative",
|
|
7164
|
+
severity: "off",
|
|
7165
|
+
fixable: false,
|
|
7166
|
+
supportedEffect: ["v3", "v4"],
|
|
7167
|
+
apply: makeGlobalDateApply(false)
|
|
7168
|
+
});
|
|
7169
|
+
|
|
7021
7170
|
// src/diagnostics/globalErrorInEffectCatch.ts
|
|
7022
7171
|
var globalErrorInEffectCatch = createDiagnostic({
|
|
7023
7172
|
name: "globalErrorInEffectCatch",
|
|
@@ -7137,46 +7286,186 @@ var globalErrorInEffectFailure = createDiagnostic({
|
|
|
7137
7286
|
})
|
|
7138
7287
|
});
|
|
7139
7288
|
|
|
7289
|
+
// src/diagnostics/globalFetchInEffect.ts
|
|
7290
|
+
var makeGlobalFetchApply = (checkInEffect) => fn(`globalFetch${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
7291
|
+
const ts = yield* service(TypeScriptApi);
|
|
7292
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
7293
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7294
|
+
const typeParser = yield* service(TypeParser);
|
|
7295
|
+
const fetchSymbol = typeChecker.resolveName("fetch", void 0, ts.SymbolFlags.Value, false);
|
|
7296
|
+
if (!fetchSymbol) return;
|
|
7297
|
+
const effectVersion = typeParser.supportedEffect();
|
|
7298
|
+
const packageName = effectVersion === "v3" ? "@effect/platform" : "effect/unstable/http";
|
|
7299
|
+
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.`;
|
|
7300
|
+
const nodeToVisit = [];
|
|
7301
|
+
const appendNodeToVisit = (node) => {
|
|
7302
|
+
nodeToVisit.push(node);
|
|
7303
|
+
return void 0;
|
|
7304
|
+
};
|
|
7305
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
7306
|
+
while (nodeToVisit.length > 0) {
|
|
7307
|
+
const node = nodeToVisit.shift();
|
|
7308
|
+
if (ts.isCallExpression(node)) {
|
|
7309
|
+
const symbol3 = typeChecker.getSymbolAtLocation(node.expression);
|
|
7310
|
+
if (symbol3 && typeCheckerUtils.resolveToGlobalSymbol(symbol3) === fetchSymbol) {
|
|
7311
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
7312
|
+
if (inEffect === checkInEffect) {
|
|
7313
|
+
report({
|
|
7314
|
+
location: node.expression,
|
|
7315
|
+
messageText,
|
|
7316
|
+
fixes: []
|
|
7317
|
+
});
|
|
7318
|
+
}
|
|
7319
|
+
}
|
|
7320
|
+
}
|
|
7321
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
7322
|
+
}
|
|
7323
|
+
});
|
|
7324
|
+
var globalFetchInEffect = createDiagnostic({
|
|
7325
|
+
name: "globalFetchInEffect",
|
|
7326
|
+
code: 63,
|
|
7327
|
+
description: "Warns when using the global fetch function inside Effect generators instead of the Effect HTTP client",
|
|
7328
|
+
group: "effectNative",
|
|
7329
|
+
severity: "off",
|
|
7330
|
+
fixable: false,
|
|
7331
|
+
supportedEffect: ["v3", "v4"],
|
|
7332
|
+
apply: makeGlobalFetchApply(true)
|
|
7333
|
+
});
|
|
7334
|
+
|
|
7140
7335
|
// src/diagnostics/globalFetch.ts
|
|
7141
7336
|
var globalFetch = createDiagnostic({
|
|
7142
7337
|
name: "globalFetch",
|
|
7143
7338
|
code: 53,
|
|
7144
|
-
description: "Warns when using the global fetch function instead of the Effect HTTP client",
|
|
7339
|
+
description: "Warns when using the global fetch function outside Effect generators instead of the Effect HTTP client",
|
|
7145
7340
|
group: "effectNative",
|
|
7146
7341
|
severity: "off",
|
|
7147
7342
|
fixable: false,
|
|
7148
7343
|
supportedEffect: ["v3", "v4"],
|
|
7149
|
-
apply:
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7344
|
+
apply: makeGlobalFetchApply(false)
|
|
7345
|
+
});
|
|
7346
|
+
|
|
7347
|
+
// src/diagnostics/globalRandomInEffect.ts
|
|
7348
|
+
var makeGlobalRandomApply = (checkInEffect) => fn(`globalRandom${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
7349
|
+
const ts = yield* service(TypeScriptApi);
|
|
7350
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
7351
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7352
|
+
const typeParser = yield* service(TypeParser);
|
|
7353
|
+
const mathSymbol = typeChecker.resolveName("Math", void 0, ts.SymbolFlags.Value, false);
|
|
7354
|
+
if (!mathSymbol) return;
|
|
7355
|
+
const nodeToVisit = [];
|
|
7356
|
+
const appendNodeToVisit = (node) => {
|
|
7357
|
+
nodeToVisit.push(node);
|
|
7358
|
+
return void 0;
|
|
7359
|
+
};
|
|
7360
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
7361
|
+
while (nodeToVisit.length > 0) {
|
|
7362
|
+
const node = nodeToVisit.shift();
|
|
7363
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
7364
|
+
if (!ts.isCallExpression(node) || !ts.isPropertyAccessExpression(node.expression) || ts.idText(node.expression.name) !== "random") continue;
|
|
7365
|
+
const symbol3 = typeChecker.getSymbolAtLocation(node.expression.expression);
|
|
7366
|
+
if (!symbol3) continue;
|
|
7367
|
+
if (typeCheckerUtils.resolveToGlobalSymbol(symbol3) !== mathSymbol) continue;
|
|
7368
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
7369
|
+
if (inEffect !== checkInEffect) continue;
|
|
7370
|
+
report({
|
|
7371
|
+
location: node,
|
|
7372
|
+
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().",
|
|
7373
|
+
fixes: []
|
|
7374
|
+
});
|
|
7375
|
+
}
|
|
7376
|
+
});
|
|
7377
|
+
var globalRandomInEffect = createDiagnostic({
|
|
7378
|
+
name: "globalRandomInEffect",
|
|
7379
|
+
code: 57,
|
|
7380
|
+
description: "Warns when using Math.random() inside Effect generators instead of the Random service",
|
|
7381
|
+
group: "effectNative",
|
|
7382
|
+
severity: "off",
|
|
7383
|
+
fixable: false,
|
|
7384
|
+
supportedEffect: ["v3", "v4"],
|
|
7385
|
+
apply: makeGlobalRandomApply(true)
|
|
7386
|
+
});
|
|
7387
|
+
|
|
7388
|
+
// src/diagnostics/globalRandom.ts
|
|
7389
|
+
var globalRandom = createDiagnostic({
|
|
7390
|
+
name: "globalRandom",
|
|
7391
|
+
code: 61,
|
|
7392
|
+
description: "Warns when using Math.random() outside Effect generators instead of the Random service",
|
|
7393
|
+
group: "effectNative",
|
|
7394
|
+
severity: "off",
|
|
7395
|
+
fixable: false,
|
|
7396
|
+
supportedEffect: ["v3", "v4"],
|
|
7397
|
+
apply: makeGlobalRandomApply(false)
|
|
7398
|
+
});
|
|
7399
|
+
|
|
7400
|
+
// src/diagnostics/globalTimersInEffect.ts
|
|
7401
|
+
var timerAlternatives = {
|
|
7402
|
+
"setTimeout": {
|
|
7403
|
+
inEffect: "Prefer using Effect.sleep or Schedule from Effect instead of setTimeout inside Effect generators.",
|
|
7404
|
+
outsideEffect: "Prefer using Effect.sleep or Schedule from Effect instead of setTimeout."
|
|
7405
|
+
},
|
|
7406
|
+
"setInterval": {
|
|
7407
|
+
inEffect: "Prefer using Schedule or Effect.repeat from Effect instead of setInterval inside Effect generators.",
|
|
7408
|
+
outsideEffect: "Prefer using Schedule or Effect.repeat from Effect instead of setInterval."
|
|
7409
|
+
}
|
|
7410
|
+
};
|
|
7411
|
+
var makeGlobalTimersApply = (checkInEffect) => fn(`globalTimers${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
7412
|
+
const ts = yield* service(TypeScriptApi);
|
|
7413
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
7414
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7415
|
+
const typeParser = yield* service(TypeParser);
|
|
7416
|
+
const globalSymbols = /* @__PURE__ */ new Map();
|
|
7417
|
+
for (const name of Object.keys(timerAlternatives)) {
|
|
7418
|
+
const symbol3 = typeChecker.resolveName(name, void 0, ts.SymbolFlags.Value, false);
|
|
7419
|
+
if (symbol3) globalSymbols.set(name, symbol3);
|
|
7420
|
+
}
|
|
7421
|
+
if (globalSymbols.size === 0) return;
|
|
7422
|
+
const nodeToVisit = [];
|
|
7423
|
+
const appendNodeToVisit = (node) => {
|
|
7424
|
+
nodeToVisit.push(node);
|
|
7425
|
+
return void 0;
|
|
7426
|
+
};
|
|
7427
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
7428
|
+
while (nodeToVisit.length > 0) {
|
|
7429
|
+
const node = nodeToVisit.shift();
|
|
7430
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
7431
|
+
if (!ts.isCallExpression(node)) continue;
|
|
7432
|
+
const symbol3 = typeChecker.getSymbolAtLocation(node.expression);
|
|
7433
|
+
if (!symbol3) continue;
|
|
7434
|
+
const resolvedSymbol = typeCheckerUtils.resolveToGlobalSymbol(symbol3);
|
|
7435
|
+
let messageText;
|
|
7436
|
+
for (const [name, symbol4] of globalSymbols) {
|
|
7437
|
+
if (resolvedSymbol === symbol4) {
|
|
7438
|
+
messageText = checkInEffect ? timerAlternatives[name].inEffect : timerAlternatives[name].outsideEffect;
|
|
7439
|
+
break;
|
|
7176
7440
|
}
|
|
7177
|
-
ts.forEachChild(node, appendNodeToVisit);
|
|
7178
7441
|
}
|
|
7179
|
-
|
|
7442
|
+
if (!messageText) continue;
|
|
7443
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
7444
|
+
if (inEffect !== checkInEffect) continue;
|
|
7445
|
+
report({ location: node, messageText, fixes: [] });
|
|
7446
|
+
}
|
|
7447
|
+
});
|
|
7448
|
+
var globalTimersInEffect = createDiagnostic({
|
|
7449
|
+
name: "globalTimersInEffect",
|
|
7450
|
+
code: 58,
|
|
7451
|
+
description: "Warns when using setTimeout/setInterval inside Effect generators instead of Effect.sleep/Schedule",
|
|
7452
|
+
group: "effectNative",
|
|
7453
|
+
severity: "off",
|
|
7454
|
+
fixable: false,
|
|
7455
|
+
supportedEffect: ["v3", "v4"],
|
|
7456
|
+
apply: makeGlobalTimersApply(true)
|
|
7457
|
+
});
|
|
7458
|
+
|
|
7459
|
+
// src/diagnostics/globalTimers.ts
|
|
7460
|
+
var globalTimers = createDiagnostic({
|
|
7461
|
+
name: "globalTimers",
|
|
7462
|
+
code: 62,
|
|
7463
|
+
description: "Warns when using setTimeout/setInterval outside Effect generators instead of Effect.sleep/Schedule",
|
|
7464
|
+
group: "effectNative",
|
|
7465
|
+
severity: "off",
|
|
7466
|
+
fixable: false,
|
|
7467
|
+
supportedEffect: ["v3", "v4"],
|
|
7468
|
+
apply: makeGlobalTimersApply(false)
|
|
7180
7469
|
});
|
|
7181
7470
|
|
|
7182
7471
|
// src/diagnostics/importFromBarrel.ts
|
|
@@ -8241,8 +8530,8 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
8241
8530
|
if (!type) continue;
|
|
8242
8531
|
const maybeEffect = yield* option(typeParser.effectYieldableType(type, unwrapped.expression));
|
|
8243
8532
|
if (!(isSome2(maybeEffect) && maybeEffect.value.A.flags & ts.TypeFlags.Never)) continue;
|
|
8244
|
-
const {
|
|
8245
|
-
if (!
|
|
8533
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
8534
|
+
if (!inEffect) continue;
|
|
8246
8535
|
const fix = [{
|
|
8247
8536
|
fixName: "missingReturnYieldStar_fix",
|
|
8248
8537
|
description: "Add return statement",
|
|
@@ -10705,11 +10994,8 @@ var preferSchemaOverJson = createDiagnostic({
|
|
|
10705
10994
|
});
|
|
10706
10995
|
const jsonMethodInEffectGen = fn("preferSchemaOverJson.jsonMethodInEffectGen")(
|
|
10707
10996
|
function* (jsonCall) {
|
|
10708
|
-
const {
|
|
10709
|
-
if (!
|
|
10710
|
-
return yield* TypeParserIssue.issue;
|
|
10711
|
-
}
|
|
10712
|
-
if (scopeNode && scopeNode !== effectGen.generatorFunction) {
|
|
10997
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(jsonCall);
|
|
10998
|
+
if (!inEffect) {
|
|
10713
10999
|
return yield* TypeParserIssue.issue;
|
|
10714
11000
|
}
|
|
10715
11001
|
return jsonCall;
|
|
@@ -10872,16 +11158,16 @@ Nested Effect-able types may be intended if you plan to later manually flatten o
|
|
|
10872
11158
|
var runEffectInsideEffect = createDiagnostic({
|
|
10873
11159
|
name: "runEffectInsideEffect",
|
|
10874
11160
|
code: 32,
|
|
10875
|
-
description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
|
|
11161
|
+
description: "Suggests using Runtime or Effect.run*With methods instead of Effect.run* inside Effect contexts",
|
|
10876
11162
|
group: "antipattern",
|
|
10877
11163
|
severity: "suggestion",
|
|
10878
11164
|
fixable: true,
|
|
10879
|
-
supportedEffect: ["v3"],
|
|
11165
|
+
supportedEffect: ["v3", "v4"],
|
|
10880
11166
|
apply: fn("runEffectInsideEffect.apply")(function* (sourceFile, report) {
|
|
10881
11167
|
const ts = yield* service(TypeScriptApi);
|
|
10882
11168
|
const typeParser = yield* service(TypeParser);
|
|
10883
11169
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
10884
|
-
|
|
11170
|
+
const supportedEffect = typeParser.supportedEffect();
|
|
10885
11171
|
const parseEffectMethod = (node, methodName) => pipe(
|
|
10886
11172
|
typeParser.isNodeReferenceToEffectModuleApi(methodName)(node),
|
|
10887
11173
|
map4(() => ({ node, methodName }))
|
|
@@ -10914,9 +11200,10 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
10914
11200
|
if (scopeNode && scopeNode !== effectGen.generatorFunction) {
|
|
10915
11201
|
const fixAddRuntime = gen(function* () {
|
|
10916
11202
|
const changeTracker = yield* service(ChangeTracker);
|
|
10917
|
-
const runtimeModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Runtime") || "Runtime";
|
|
10918
11203
|
const effectModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Effect") || "Effect";
|
|
11204
|
+
const runtimeModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Runtime") || "Runtime";
|
|
10919
11205
|
let runtimeIdentifier = void 0;
|
|
11206
|
+
let servicesIdentifier = void 0;
|
|
10920
11207
|
for (const statement of effectGen.generatorFunction.body.statements) {
|
|
10921
11208
|
if (ts.isVariableStatement(statement) && statement.declarationList.declarations.length === 1) {
|
|
10922
11209
|
const declaration = statement.declarationList.declarations[0];
|
|
@@ -10930,11 +11217,46 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
10930
11217
|
if (isSome2(maybeEffectRuntime) && ts.isIdentifier(declaration.name)) {
|
|
10931
11218
|
runtimeIdentifier = ts.idText(declaration.name);
|
|
10932
11219
|
}
|
|
11220
|
+
const maybeEffectServices = yield* pipe(
|
|
11221
|
+
typeParser.isNodeReferenceToEffectModuleApi("services")(yieldedExpression.expression),
|
|
11222
|
+
option
|
|
11223
|
+
);
|
|
11224
|
+
if (isSome2(maybeEffectServices) && ts.isIdentifier(declaration.name)) {
|
|
11225
|
+
servicesIdentifier = ts.idText(declaration.name);
|
|
11226
|
+
}
|
|
10933
11227
|
}
|
|
10934
11228
|
}
|
|
10935
11229
|
}
|
|
10936
11230
|
}
|
|
10937
|
-
if (!
|
|
11231
|
+
if (supportedEffect === "v4" && !servicesIdentifier) {
|
|
11232
|
+
changeTracker.insertNodeAt(
|
|
11233
|
+
sourceFile,
|
|
11234
|
+
effectGen.body.statements[0].pos,
|
|
11235
|
+
ts.factory.createVariableStatement(
|
|
11236
|
+
void 0,
|
|
11237
|
+
ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration(
|
|
11238
|
+
"effectServices",
|
|
11239
|
+
void 0,
|
|
11240
|
+
void 0,
|
|
11241
|
+
ts.factory.createYieldExpression(
|
|
11242
|
+
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
11243
|
+
ts.factory.createCallExpression(
|
|
11244
|
+
ts.factory.createPropertyAccessExpression(
|
|
11245
|
+
ts.factory.createIdentifier(effectModuleIdentifier),
|
|
11246
|
+
"services"
|
|
11247
|
+
),
|
|
11248
|
+
[ts.factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)],
|
|
11249
|
+
[]
|
|
11250
|
+
)
|
|
11251
|
+
)
|
|
11252
|
+
)], ts.NodeFlags.Const)
|
|
11253
|
+
),
|
|
11254
|
+
{
|
|
11255
|
+
prefix: "\n",
|
|
11256
|
+
suffix: "\n"
|
|
11257
|
+
}
|
|
11258
|
+
);
|
|
11259
|
+
} else if (supportedEffect === "v3" && !runtimeIdentifier) {
|
|
10938
11260
|
changeTracker.insertNodeAt(
|
|
10939
11261
|
sourceFile,
|
|
10940
11262
|
effectGen.body.statements[0].pos,
|
|
@@ -10970,16 +11292,19 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
10970
11292
|
changeTracker.insertText(
|
|
10971
11293
|
sourceFile,
|
|
10972
11294
|
node.arguments[0].pos,
|
|
10973
|
-
`${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
|
|
11295
|
+
supportedEffect === "v4" ? `${effectModuleIdentifier}.${isEffectRunCall.value.methodName}With(${servicesIdentifier || "effectServices"})(` : `${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
|
|
10974
11296
|
);
|
|
10975
11297
|
});
|
|
11298
|
+
const v4MethodName = `${isEffectRunCall.value.methodName}With`;
|
|
11299
|
+
const messageText = supportedEffect === "v4" ? `Using ${nodeText} inside an Effect is not recommended. The same services should generally be used instead to run child effects.
|
|
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.`;
|
|
10976
11302
|
report({
|
|
10977
11303
|
location: node.expression,
|
|
10978
|
-
messageText
|
|
10979
|
-
Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`,
|
|
11304
|
+
messageText,
|
|
10980
11305
|
fixes: [{
|
|
10981
11306
|
fixName: "runEffectInsideEffect_fix",
|
|
10982
|
-
description: "Use a runtime to run the Effect",
|
|
11307
|
+
description: supportedEffect === "v4" ? "Use the current services to run the Effect" : "Use a runtime to run the Effect",
|
|
10983
11308
|
apply: fixAddRuntime
|
|
10984
11309
|
}]
|
|
10985
11310
|
});
|
|
@@ -11125,9 +11450,8 @@ var schemaSyncInEffect = createDiagnostic({
|
|
|
11125
11450
|
option
|
|
11126
11451
|
);
|
|
11127
11452
|
if (isNone2(isSchemaSyncCall)) continue;
|
|
11128
|
-
const {
|
|
11129
|
-
if (!
|
|
11130
|
-
if (scopeNode && scopeNode !== effectGen.generatorFunction) continue;
|
|
11453
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
11454
|
+
if (!inEffect) continue;
|
|
11131
11455
|
const nodeText = sourceFile.text.substring(
|
|
11132
11456
|
ts.getTokenPosOfNode(node.expression, sourceFile),
|
|
11133
11457
|
node.expression.end
|
|
@@ -11969,6 +12293,7 @@ var diagnostics = [
|
|
|
11969
12293
|
unnecessaryPipe,
|
|
11970
12294
|
genericEffectServices,
|
|
11971
12295
|
globalFetch,
|
|
12296
|
+
globalFetchInEffect,
|
|
11972
12297
|
returnEffectInGen,
|
|
11973
12298
|
tryCatchInEffectGen,
|
|
11974
12299
|
importFromBarrel,
|
|
@@ -12000,7 +12325,15 @@ var diagnostics = [
|
|
|
12000
12325
|
preferSchemaOverJson,
|
|
12001
12326
|
extendsNativeError,
|
|
12002
12327
|
serviceNotAsClass,
|
|
12003
|
-
nodeBuiltinImport
|
|
12328
|
+
nodeBuiltinImport,
|
|
12329
|
+
globalDate,
|
|
12330
|
+
globalDateInEffect,
|
|
12331
|
+
globalConsole,
|
|
12332
|
+
globalConsoleInEffect,
|
|
12333
|
+
globalRandom,
|
|
12334
|
+
globalRandomInEffect,
|
|
12335
|
+
globalTimers,
|
|
12336
|
+
globalTimersInEffect
|
|
12004
12337
|
];
|
|
12005
12338
|
|
|
12006
12339
|
// src/transform.ts
|