@effect/language-service 0.21.3 → 0.21.5
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/index.js +249 -160
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +249 -160
- package/transform.js.map +1 -1
package/index.js
CHANGED
|
@@ -1766,33 +1766,6 @@ var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
|
|
|
1766
1766
|
const execute = fn("LSP.ruleExecutor")(function* (rule) {
|
|
1767
1767
|
const ruleNameLowered = rule.name.toLowerCase();
|
|
1768
1768
|
if (skippedRules.indexOf(ruleNameLowered) > -1) return [];
|
|
1769
|
-
let modifiedDiagnostics = yield* rule.apply(sourceFile);
|
|
1770
|
-
const newLevel = pluginOptions.diagnosticSeverity[ruleNameLowered];
|
|
1771
|
-
if (newLevel) {
|
|
1772
|
-
for (const emitted of modifiedDiagnostics) {
|
|
1773
|
-
emitted.category = newLevel && newLevel in levelToDiagnosticCategory ? levelToDiagnosticCategory[newLevel] : emitted.category;
|
|
1774
|
-
}
|
|
1775
|
-
}
|
|
1776
|
-
for (const emitted of modifiedDiagnostics.slice(0)) {
|
|
1777
|
-
let newLevel2 = void 0;
|
|
1778
|
-
if (!(ruleNameLowered in sectionOverrides || ruleNameLowered in lineOverrides)) continue;
|
|
1779
|
-
const lineOverride = (lineOverrides[ruleNameLowered] || []).find(
|
|
1780
|
-
(_) => _.pos < emitted.node.getStart(sourceFile) && _.end >= emitted.node.getEnd()
|
|
1781
|
-
);
|
|
1782
|
-
if (lineOverride) {
|
|
1783
|
-
newLevel2 = lineOverride.level;
|
|
1784
|
-
} else {
|
|
1785
|
-
const sectionOverride = (sectionOverrides[ruleNameLowered] || []).find(
|
|
1786
|
-
(_) => _.pos < emitted.node.getStart(sourceFile)
|
|
1787
|
-
);
|
|
1788
|
-
if (sectionOverride) newLevel2 = sectionOverride.level;
|
|
1789
|
-
}
|
|
1790
|
-
if (newLevel2 === "off") {
|
|
1791
|
-
modifiedDiagnostics = modifiedDiagnostics.filter((_) => _ !== emitted);
|
|
1792
|
-
} else {
|
|
1793
|
-
emitted.category = newLevel2 && newLevel2 in levelToDiagnosticCategory ? levelToDiagnosticCategory[newLevel2] : emitted.category;
|
|
1794
|
-
}
|
|
1795
|
-
}
|
|
1796
1769
|
const fixByDisableNextLine = (_) => ({
|
|
1797
1770
|
fixName: rule.name + "_skipNextLine",
|
|
1798
1771
|
description: "Disable " + rule.name + " for this line",
|
|
@@ -1825,11 +1798,34 @@ var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
|
|
|
1825
1798
|
)
|
|
1826
1799
|
)
|
|
1827
1800
|
};
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1801
|
+
let modifiedDiagnostics = [];
|
|
1802
|
+
yield* rule.apply(sourceFile, (entry) => {
|
|
1803
|
+
modifiedDiagnostics.push({
|
|
1804
|
+
...entry,
|
|
1805
|
+
fixes: entry.fixes.concat([fixByDisableNextLine(entry), fixByDisableEntireFile])
|
|
1806
|
+
});
|
|
1807
|
+
});
|
|
1808
|
+
if (!(ruleNameLowered in pluginOptions.diagnosticSeverity || ruleNameLowered in sectionOverrides || ruleNameLowered in lineOverrides)) return modifiedDiagnostics;
|
|
1809
|
+
for (const emitted of modifiedDiagnostics.slice(0)) {
|
|
1810
|
+
let newLevel = pluginOptions.diagnosticSeverity[ruleNameLowered];
|
|
1811
|
+
const lineOverride = (lineOverrides[ruleNameLowered] || []).find(
|
|
1812
|
+
(_) => _.pos < emitted.node.getStart(sourceFile) && _.end >= emitted.node.getEnd()
|
|
1813
|
+
);
|
|
1814
|
+
if (lineOverride) {
|
|
1815
|
+
newLevel = lineOverride.level;
|
|
1816
|
+
} else {
|
|
1817
|
+
const sectionOverride = (sectionOverrides[ruleNameLowered] || []).find(
|
|
1818
|
+
(_) => _.pos < emitted.node.getStart(sourceFile)
|
|
1819
|
+
);
|
|
1820
|
+
if (sectionOverride) newLevel = sectionOverride.level;
|
|
1821
|
+
}
|
|
1822
|
+
if (newLevel === "off") {
|
|
1823
|
+
modifiedDiagnostics = modifiedDiagnostics.filter((_) => _ !== emitted);
|
|
1824
|
+
} else {
|
|
1825
|
+
emitted.category = newLevel && newLevel in levelToDiagnosticCategory ? levelToDiagnosticCategory[newLevel] : emitted.category;
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
return modifiedDiagnostics;
|
|
1833
1829
|
});
|
|
1834
1830
|
return { execute };
|
|
1835
1831
|
}
|
|
@@ -2100,6 +2096,16 @@ function make4(ts, typeChecker) {
|
|
|
2100
2096
|
"TypeParser.effectType",
|
|
2101
2097
|
(type) => type
|
|
2102
2098
|
);
|
|
2099
|
+
const strictEffectType = cachedBy(
|
|
2100
|
+
fn("TypeParser.strictEffectType")(function* (type, atLocation) {
|
|
2101
|
+
if (type.symbol.name !== "Effect" || type.aliasSymbol) {
|
|
2102
|
+
return yield* typeParserIssue("Type name should be Effect with no alias symbol", type, atLocation);
|
|
2103
|
+
}
|
|
2104
|
+
return yield* effectType(type, atLocation);
|
|
2105
|
+
}),
|
|
2106
|
+
"TypeParser.strictEffectType",
|
|
2107
|
+
(type) => type
|
|
2108
|
+
);
|
|
2103
2109
|
const layerType = cachedBy(
|
|
2104
2110
|
fn("TypeParser.layerType")(function* (type, atLocation) {
|
|
2105
2111
|
yield* pipeableType(type, atLocation);
|
|
@@ -2451,6 +2457,7 @@ function make4(ts, typeChecker) {
|
|
|
2451
2457
|
);
|
|
2452
2458
|
return {
|
|
2453
2459
|
effectType,
|
|
2460
|
+
strictEffectType,
|
|
2454
2461
|
layerType,
|
|
2455
2462
|
fiberType,
|
|
2456
2463
|
effectSubtype,
|
|
@@ -2537,6 +2544,7 @@ var getMissingTypeEntriesInTargetType = fn(
|
|
|
2537
2544
|
"TypeCheckerApi.getMissingTypeEntriesInTargetType"
|
|
2538
2545
|
)(
|
|
2539
2546
|
function* (realType, expectedType) {
|
|
2547
|
+
if (realType === expectedType) return [];
|
|
2540
2548
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
2541
2549
|
const result = [];
|
|
2542
2550
|
let toTest = [realType];
|
|
@@ -2846,12 +2854,11 @@ var programResolvedCacheSize = /* @__PURE__ */ new Map();
|
|
|
2846
2854
|
var duplicatePackage = createDiagnostic({
|
|
2847
2855
|
name: "duplicatePackage",
|
|
2848
2856
|
code: 6,
|
|
2849
|
-
apply: fn("duplicatePackage.apply")(function* (sourceFile) {
|
|
2857
|
+
apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
|
|
2850
2858
|
const ts = yield* service(TypeScriptApi);
|
|
2851
2859
|
const program = yield* service(TypeScriptProgram);
|
|
2852
2860
|
const options = yield* service(LanguageServicePluginOptions);
|
|
2853
|
-
|
|
2854
|
-
if (sourceFile.statements.length < 1) return [];
|
|
2861
|
+
if (sourceFile.statements.length < 1) return;
|
|
2855
2862
|
let resolvedPackages = checkedPackagesCache.get(sourceFile.fileName) || {};
|
|
2856
2863
|
const newResolvedModuleSize = hasProperty(program, "resolvedModules") && hasProperty(program.resolvedModules, "size") && isNumber(program.resolvedModules.size) ? program.resolvedModules.size : 0;
|
|
2857
2864
|
const oldResolvedSize = programResolvedCacheSize.get(sourceFile.fileName) || -1;
|
|
@@ -2875,7 +2882,7 @@ var duplicatePackage = createDiagnostic({
|
|
|
2875
2882
|
for (const packageName of Object.keys(resolvedPackages)) {
|
|
2876
2883
|
if (Object.keys(resolvedPackages[packageName]).length > 1) {
|
|
2877
2884
|
const versions = Object.keys(resolvedPackages[packageName]);
|
|
2878
|
-
|
|
2885
|
+
report({
|
|
2879
2886
|
node: sourceFile.statements[0],
|
|
2880
2887
|
category: ts.DiagnosticCategory.Warning,
|
|
2881
2888
|
messageText: `Package ${packageName} is referenced multiple times with different versions (${versions.join(", ")}) and may cause unexpected type errors.
|
|
@@ -2887,7 +2894,6 @@ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageNam
|
|
|
2887
2894
|
});
|
|
2888
2895
|
}
|
|
2889
2896
|
}
|
|
2890
|
-
return effectDiagnostics;
|
|
2891
2897
|
})
|
|
2892
2898
|
});
|
|
2893
2899
|
|
|
@@ -2895,7 +2901,7 @@ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageNam
|
|
|
2895
2901
|
var floatingEffect = createDiagnostic({
|
|
2896
2902
|
name: "floatingEffect",
|
|
2897
2903
|
code: 3,
|
|
2898
|
-
apply: fn("floatingEffect.apply")(function* (sourceFile) {
|
|
2904
|
+
apply: fn("floatingEffect.apply")(function* (sourceFile, report) {
|
|
2899
2905
|
const ts = yield* service(TypeScriptApi);
|
|
2900
2906
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
2901
2907
|
const typeParser = yield* service(TypeParser);
|
|
@@ -2906,7 +2912,6 @@ var floatingEffect = createDiagnostic({
|
|
|
2906
2912
|
if (ts.isBinaryExpression(expression) && expression.operatorToken && (expression.operatorToken.kind === ts.SyntaxKind.EqualsToken || expression.operatorToken.kind === ts.SyntaxKind.QuestionQuestionEqualsToken || expression.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken || expression.operatorToken.kind === ts.SyntaxKind.BarBarEqualsToken)) return false;
|
|
2907
2913
|
return true;
|
|
2908
2914
|
}
|
|
2909
|
-
const effectDiagnostics = [];
|
|
2910
2915
|
const nodeToVisit = [];
|
|
2911
2916
|
const appendNodeToVisit = (node) => {
|
|
2912
2917
|
nodeToVisit.push(node);
|
|
@@ -2926,7 +2931,7 @@ var floatingEffect = createDiagnostic({
|
|
|
2926
2931
|
option
|
|
2927
2932
|
);
|
|
2928
2933
|
if (isNone2(allowedFloatingEffects)) {
|
|
2929
|
-
|
|
2934
|
+
report({
|
|
2930
2935
|
node,
|
|
2931
2936
|
category: ts.DiagnosticCategory.Error,
|
|
2932
2937
|
messageText: `Effect must be yielded or assigned to a variable.`,
|
|
@@ -2935,7 +2940,52 @@ var floatingEffect = createDiagnostic({
|
|
|
2935
2940
|
}
|
|
2936
2941
|
}
|
|
2937
2942
|
}
|
|
2938
|
-
|
|
2943
|
+
})
|
|
2944
|
+
});
|
|
2945
|
+
|
|
2946
|
+
// src/diagnostics/genericEffectServices.ts
|
|
2947
|
+
var genericEffectServices = createDiagnostic({
|
|
2948
|
+
name: "genericEffectServices",
|
|
2949
|
+
code: 10,
|
|
2950
|
+
apply: fn("genericEffectServices.apply")(function* (sourceFile, report) {
|
|
2951
|
+
const ts = yield* service(TypeScriptApi);
|
|
2952
|
+
const typeParser = yield* service(TypeParser);
|
|
2953
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
2954
|
+
const nodeToVisit = [];
|
|
2955
|
+
const appendNodeToVisit = (node) => {
|
|
2956
|
+
nodeToVisit.push(node);
|
|
2957
|
+
return void 0;
|
|
2958
|
+
};
|
|
2959
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
2960
|
+
while (nodeToVisit.length > 0) {
|
|
2961
|
+
const node = nodeToVisit.shift();
|
|
2962
|
+
const typesToCheck = [];
|
|
2963
|
+
if (ts.isClassDeclaration(node) && node.name && node.typeParameters && node.heritageClauses) {
|
|
2964
|
+
const classSym = typeChecker.getSymbolAtLocation(node.name);
|
|
2965
|
+
if (classSym) {
|
|
2966
|
+
const type = typeChecker.getTypeOfSymbol(classSym);
|
|
2967
|
+
typesToCheck.push([type, node.name]);
|
|
2968
|
+
}
|
|
2969
|
+
} else {
|
|
2970
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
2971
|
+
continue;
|
|
2972
|
+
}
|
|
2973
|
+
for (const [type, reportAt] of typesToCheck) {
|
|
2974
|
+
yield* pipe(
|
|
2975
|
+
typeParser.contextTag(type, node),
|
|
2976
|
+
map4(() => {
|
|
2977
|
+
report({
|
|
2978
|
+
node: reportAt,
|
|
2979
|
+
category: ts.DiagnosticCategory.Warning,
|
|
2980
|
+
messageText: `Effect Services with type parameters are not supported because they cannot be properly discriminated at runtime, which may cause unexpected behavior.`,
|
|
2981
|
+
fixes: []
|
|
2982
|
+
});
|
|
2983
|
+
}),
|
|
2984
|
+
orElse3(() => sync(() => ts.forEachChild(node, appendNodeToVisit))),
|
|
2985
|
+
ignore
|
|
2986
|
+
);
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2939
2989
|
})
|
|
2940
2990
|
});
|
|
2941
2991
|
|
|
@@ -2943,12 +2993,11 @@ var floatingEffect = createDiagnostic({
|
|
|
2943
2993
|
var leakingRequirements = createDiagnostic({
|
|
2944
2994
|
name: "leakingRequirements",
|
|
2945
2995
|
code: 8,
|
|
2946
|
-
apply: fn("leakingRequirements.apply")(function* (sourceFile) {
|
|
2996
|
+
apply: fn("leakingRequirements.apply")(function* (sourceFile, report) {
|
|
2947
2997
|
const ts = yield* service(TypeScriptApi);
|
|
2948
2998
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
2949
2999
|
const typeParser = yield* service(TypeParser);
|
|
2950
3000
|
const typeOrder = yield* deterministicTypeOrder;
|
|
2951
|
-
const effectDiagnostics = [];
|
|
2952
3001
|
const parseLeakedRequirements = cachedBy(
|
|
2953
3002
|
fn("leakingServices.checkServiceLeaking")(
|
|
2954
3003
|
function* (service2, atLocation) {
|
|
@@ -2999,7 +3048,7 @@ var leakingRequirements = createDiagnostic({
|
|
|
2999
3048
|
);
|
|
3000
3049
|
function reportLeakingRequirements(node, requirements) {
|
|
3001
3050
|
if (requirements.length === 0) return;
|
|
3002
|
-
|
|
3051
|
+
report({
|
|
3003
3052
|
node,
|
|
3004
3053
|
category: ts.DiagnosticCategory.Warning,
|
|
3005
3054
|
messageText: `This Service is leaking the ${requirements.map((_) => typeChecker.typeToString(_)).join(" | ")} requirement`,
|
|
@@ -3017,7 +3066,7 @@ var leakingRequirements = createDiagnostic({
|
|
|
3017
3066
|
const typesToCheck = [];
|
|
3018
3067
|
if (ts.isCallExpression(node)) {
|
|
3019
3068
|
typesToCheck.push([typeChecker.getTypeAtLocation(node), node]);
|
|
3020
|
-
} else if (ts.isClassDeclaration(node) && node.name) {
|
|
3069
|
+
} else if (ts.isClassDeclaration(node) && node.name && node.heritageClauses) {
|
|
3021
3070
|
const classSym = typeChecker.getSymbolAtLocation(node.name);
|
|
3022
3071
|
if (classSym) {
|
|
3023
3072
|
const type = typeChecker.getTypeOfSymbol(classSym);
|
|
@@ -3041,7 +3090,6 @@ var leakingRequirements = createDiagnostic({
|
|
|
3041
3090
|
);
|
|
3042
3091
|
}
|
|
3043
3092
|
}
|
|
3044
|
-
return effectDiagnostics;
|
|
3045
3093
|
})
|
|
3046
3094
|
});
|
|
3047
3095
|
|
|
@@ -3049,28 +3097,23 @@ var leakingRequirements = createDiagnostic({
|
|
|
3049
3097
|
var missingEffectContext = createDiagnostic({
|
|
3050
3098
|
name: "missingEffectContext",
|
|
3051
3099
|
code: 1,
|
|
3052
|
-
apply: fn("missingEffectContext.apply")(function* (sourceFile) {
|
|
3100
|
+
apply: fn("missingEffectContext.apply")(function* (sourceFile, report) {
|
|
3053
3101
|
const ts = yield* service(TypeScriptApi);
|
|
3054
3102
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
3055
3103
|
const typeParser = yield* service(TypeParser);
|
|
3056
3104
|
const typeOrder = yield* deterministicTypeOrder;
|
|
3057
|
-
const checkForMissingContextTypes =
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
)
|
|
3068
|
-
|
|
3069
|
-
realEffect.R,
|
|
3070
|
-
expectedEffect.R
|
|
3071
|
-
);
|
|
3072
|
-
});
|
|
3073
|
-
const effectDiagnostics = [];
|
|
3105
|
+
const checkForMissingContextTypes = (node, expectedType, valueNode, realType) => pipe(
|
|
3106
|
+
all2(
|
|
3107
|
+
typeParser.effectType(expectedType, node),
|
|
3108
|
+
typeParser.effectType(realType, valueNode)
|
|
3109
|
+
),
|
|
3110
|
+
flatMap3(
|
|
3111
|
+
([expectedEffect, realEffect]) => getMissingTypeEntriesInTargetType(
|
|
3112
|
+
realEffect.R,
|
|
3113
|
+
expectedEffect.R
|
|
3114
|
+
)
|
|
3115
|
+
)
|
|
3116
|
+
);
|
|
3074
3117
|
const sortTypes = sort(typeOrder);
|
|
3075
3118
|
const entries = yield* expectedAndRealType(sourceFile);
|
|
3076
3119
|
for (const [node, expectedType, valueNode, realType] of entries) {
|
|
@@ -3084,7 +3127,7 @@ var missingEffectContext = createDiagnostic({
|
|
|
3084
3127
|
orElse3(() => succeed([]))
|
|
3085
3128
|
);
|
|
3086
3129
|
if (missingContext.length > 0) {
|
|
3087
|
-
|
|
3130
|
+
report(
|
|
3088
3131
|
{
|
|
3089
3132
|
node,
|
|
3090
3133
|
category: ts.DiagnosticCategory.Error,
|
|
@@ -3094,7 +3137,6 @@ var missingEffectContext = createDiagnostic({
|
|
|
3094
3137
|
);
|
|
3095
3138
|
}
|
|
3096
3139
|
}
|
|
3097
|
-
return effectDiagnostics;
|
|
3098
3140
|
})
|
|
3099
3141
|
});
|
|
3100
3142
|
|
|
@@ -3102,28 +3144,23 @@ var missingEffectContext = createDiagnostic({
|
|
|
3102
3144
|
var missingEffectError = createDiagnostic({
|
|
3103
3145
|
name: "missingEffectError",
|
|
3104
3146
|
code: 1,
|
|
3105
|
-
apply: fn("missingEffectError.apply")(function* (sourceFile) {
|
|
3147
|
+
apply: fn("missingEffectError.apply")(function* (sourceFile, report) {
|
|
3106
3148
|
const ts = yield* service(TypeScriptApi);
|
|
3107
3149
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
3108
3150
|
const typeParser = yield* service(TypeParser);
|
|
3109
3151
|
const typeOrder = yield* deterministicTypeOrder;
|
|
3110
|
-
const checkForMissingErrorTypes =
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
realType,
|
|
3118
|
-
valueNode
|
|
3119
|
-
);
|
|
3120
|
-
return yield* getMissingTypeEntriesInTargetType(
|
|
3152
|
+
const checkForMissingErrorTypes = (node, expectedType, valueNode, realType) => pipe(
|
|
3153
|
+
all2(
|
|
3154
|
+
typeParser.effectType(expectedType, node),
|
|
3155
|
+
typeParser.effectType(realType, valueNode)
|
|
3156
|
+
),
|
|
3157
|
+
flatMap3(
|
|
3158
|
+
([expectedEffect, realEffect]) => getMissingTypeEntriesInTargetType(
|
|
3121
3159
|
realEffect.E,
|
|
3122
3160
|
expectedEffect.E
|
|
3123
|
-
)
|
|
3124
|
-
|
|
3161
|
+
)
|
|
3162
|
+
)
|
|
3125
3163
|
);
|
|
3126
|
-
const effectDiagnostics = [];
|
|
3127
3164
|
const sortTypes = sort(typeOrder);
|
|
3128
3165
|
const entries = yield* expectedAndRealType(sourceFile);
|
|
3129
3166
|
for (const [node, expectedType, valueNode, realType] of entries) {
|
|
@@ -3137,7 +3174,7 @@ var missingEffectError = createDiagnostic({
|
|
|
3137
3174
|
orElse3(() => succeed([]))
|
|
3138
3175
|
);
|
|
3139
3176
|
if (missingContext.length > 0) {
|
|
3140
|
-
|
|
3177
|
+
report(
|
|
3141
3178
|
{
|
|
3142
3179
|
node,
|
|
3143
3180
|
category: ts.DiagnosticCategory.Error,
|
|
@@ -3147,7 +3184,6 @@ var missingEffectError = createDiagnostic({
|
|
|
3147
3184
|
);
|
|
3148
3185
|
}
|
|
3149
3186
|
}
|
|
3150
|
-
return effectDiagnostics;
|
|
3151
3187
|
})
|
|
3152
3188
|
});
|
|
3153
3189
|
|
|
@@ -3155,12 +3191,10 @@ var missingEffectError = createDiagnostic({
|
|
|
3155
3191
|
var missingReturnYieldStar = createDiagnostic({
|
|
3156
3192
|
name: "missingReturnYieldStar",
|
|
3157
3193
|
code: 7,
|
|
3158
|
-
apply: fn("missingReturnYieldStar.apply")(function* (sourceFile) {
|
|
3194
|
+
apply: fn("missingReturnYieldStar.apply")(function* (sourceFile, report) {
|
|
3159
3195
|
const ts = yield* service(TypeScriptApi);
|
|
3160
3196
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
3161
3197
|
const typeParser = yield* service(TypeParser);
|
|
3162
|
-
const effectDiagnostics = [];
|
|
3163
|
-
const brokenYields = /* @__PURE__ */ new Set();
|
|
3164
3198
|
const nodeToVisit = [];
|
|
3165
3199
|
const appendNodeToVisit = (node) => {
|
|
3166
3200
|
nodeToVisit.push(node);
|
|
@@ -3188,36 +3222,32 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
3188
3222
|
option
|
|
3189
3223
|
);
|
|
3190
3224
|
if (isSome2(effectGenLike)) {
|
|
3191
|
-
|
|
3225
|
+
const fix = node.expression ? [{
|
|
3226
|
+
fixName: "missingReturnYieldStar_fix",
|
|
3227
|
+
description: "Add return statement",
|
|
3228
|
+
apply: gen2(function* () {
|
|
3229
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
3230
|
+
changeTracker.replaceNode(
|
|
3231
|
+
sourceFile,
|
|
3232
|
+
node,
|
|
3233
|
+
ts.factory.createReturnStatement(
|
|
3234
|
+
node
|
|
3235
|
+
)
|
|
3236
|
+
);
|
|
3237
|
+
})
|
|
3238
|
+
}] : [];
|
|
3239
|
+
report({
|
|
3240
|
+
node,
|
|
3241
|
+
category: ts.DiagnosticCategory.Error,
|
|
3242
|
+
messageText: `Yielded Effect never succeeds, so it is best to use a 'return yield*' instead.`,
|
|
3243
|
+
fixes: fix
|
|
3244
|
+
});
|
|
3192
3245
|
}
|
|
3193
3246
|
}
|
|
3194
3247
|
}
|
|
3195
3248
|
}
|
|
3196
3249
|
}
|
|
3197
3250
|
}
|
|
3198
|
-
brokenYields.forEach((node) => {
|
|
3199
|
-
const fix = node.expression ? [{
|
|
3200
|
-
fixName: "missingReturnYieldStar_fix",
|
|
3201
|
-
description: "Add return statement",
|
|
3202
|
-
apply: gen2(function* () {
|
|
3203
|
-
const changeTracker = yield* service(ChangeTracker);
|
|
3204
|
-
changeTracker.replaceNode(
|
|
3205
|
-
sourceFile,
|
|
3206
|
-
node,
|
|
3207
|
-
ts.factory.createReturnStatement(
|
|
3208
|
-
node
|
|
3209
|
-
)
|
|
3210
|
-
);
|
|
3211
|
-
})
|
|
3212
|
-
}] : [];
|
|
3213
|
-
effectDiagnostics.push({
|
|
3214
|
-
node,
|
|
3215
|
-
category: ts.DiagnosticCategory.Error,
|
|
3216
|
-
messageText: `Yielded Effect never succeeds, so it is best to use a 'return yield*' instead.`,
|
|
3217
|
-
fixes: fix
|
|
3218
|
-
});
|
|
3219
|
-
});
|
|
3220
|
-
return effectDiagnostics;
|
|
3221
3251
|
})
|
|
3222
3252
|
});
|
|
3223
3253
|
|
|
@@ -3225,10 +3255,9 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
3225
3255
|
var missingStarInYieldEffectGen = createDiagnostic({
|
|
3226
3256
|
name: "missingStarInYieldEffectGen",
|
|
3227
3257
|
code: 4,
|
|
3228
|
-
apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile) {
|
|
3258
|
+
apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile, report) {
|
|
3229
3259
|
const ts = yield* service(TypeScriptApi);
|
|
3230
3260
|
const typeParser = yield* service(TypeParser);
|
|
3231
|
-
const effectDiagnostics = [];
|
|
3232
3261
|
const brokenGenerators = /* @__PURE__ */ new Set();
|
|
3233
3262
|
const brokenYields = /* @__PURE__ */ new Set();
|
|
3234
3263
|
const nodeToVisit = [];
|
|
@@ -3263,7 +3292,7 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
3263
3292
|
}
|
|
3264
3293
|
}
|
|
3265
3294
|
brokenGenerators.forEach(
|
|
3266
|
-
(node) =>
|
|
3295
|
+
(node) => report({
|
|
3267
3296
|
node,
|
|
3268
3297
|
category: ts.DiagnosticCategory.Error,
|
|
3269
3298
|
messageText: `Seems like you used yield instead of yield* inside this Effect.gen.`,
|
|
@@ -3286,14 +3315,78 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
3286
3315
|
);
|
|
3287
3316
|
})
|
|
3288
3317
|
}] : [];
|
|
3289
|
-
|
|
3318
|
+
report({
|
|
3290
3319
|
node,
|
|
3291
3320
|
category: ts.DiagnosticCategory.Error,
|
|
3292
3321
|
messageText: `When yielding Effects inside Effect.gen, you should use yield* instead of yield.`,
|
|
3293
3322
|
fixes: fix
|
|
3294
3323
|
});
|
|
3295
3324
|
});
|
|
3296
|
-
|
|
3325
|
+
})
|
|
3326
|
+
});
|
|
3327
|
+
|
|
3328
|
+
// src/diagnostics/returnEffectInGen.ts
|
|
3329
|
+
var returnEffectInGen = createDiagnostic({
|
|
3330
|
+
name: "returnEffectInGen",
|
|
3331
|
+
code: 11,
|
|
3332
|
+
apply: fn("returnEffectInGen.apply")(function* (sourceFile, report) {
|
|
3333
|
+
const ts = yield* service(TypeScriptApi);
|
|
3334
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
3335
|
+
const typeParser = yield* service(TypeParser);
|
|
3336
|
+
const nodeToVisit = [];
|
|
3337
|
+
const appendNodeToVisit = (node) => {
|
|
3338
|
+
nodeToVisit.push(node);
|
|
3339
|
+
return void 0;
|
|
3340
|
+
};
|
|
3341
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
3342
|
+
while (nodeToVisit.length > 0) {
|
|
3343
|
+
const node = nodeToVisit.shift();
|
|
3344
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
3345
|
+
if (ts.isReturnStatement(node) && node.expression) {
|
|
3346
|
+
if (ts.isYieldExpression(node.expression)) continue;
|
|
3347
|
+
const generatorOrRegularFunction = ts.findAncestor(
|
|
3348
|
+
node,
|
|
3349
|
+
(_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_) || ts.isArrowFunction(_) || ts.isGetAccessor(_)
|
|
3350
|
+
);
|
|
3351
|
+
if (!(generatorOrRegularFunction && "asteriskToken" in generatorOrRegularFunction && generatorOrRegularFunction.asteriskToken)) continue;
|
|
3352
|
+
const type = typeChecker.getTypeAtLocation(node.expression);
|
|
3353
|
+
const maybeEffect = yield* option(typeParser.strictEffectType(type, node.expression));
|
|
3354
|
+
if (isSome2(maybeEffect)) {
|
|
3355
|
+
if (generatorOrRegularFunction && generatorOrRegularFunction.parent) {
|
|
3356
|
+
const effectGenNode = generatorOrRegularFunction.parent;
|
|
3357
|
+
yield* pipe(
|
|
3358
|
+
typeParser.effectGen(effectGenNode),
|
|
3359
|
+
orElse3(() => typeParser.effectFnUntracedGen(effectGenNode)),
|
|
3360
|
+
orElse3(() => typeParser.effectFnGen(effectGenNode)),
|
|
3361
|
+
map4(() => {
|
|
3362
|
+
const fix = node.expression ? [{
|
|
3363
|
+
fixName: "returnEffectInGen_fix",
|
|
3364
|
+
description: "Add yield* statement",
|
|
3365
|
+
apply: gen2(function* () {
|
|
3366
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
3367
|
+
changeTracker.replaceNode(
|
|
3368
|
+
sourceFile,
|
|
3369
|
+
node.expression,
|
|
3370
|
+
ts.factory.createYieldExpression(
|
|
3371
|
+
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
3372
|
+
node.expression
|
|
3373
|
+
)
|
|
3374
|
+
);
|
|
3375
|
+
})
|
|
3376
|
+
}] : [];
|
|
3377
|
+
report({
|
|
3378
|
+
node,
|
|
3379
|
+
category: ts.DiagnosticCategory.Suggestion,
|
|
3380
|
+
messageText: `You are returning an Effect-able type inside a generator function, and will result in nested Effect<Effect<...>>. Maybe you wanted to return yield* instead? Nested Effect-able types may be intended if you plan to later manually flatten or unwrap this Effect.`,
|
|
3381
|
+
fixes: fix
|
|
3382
|
+
});
|
|
3383
|
+
}),
|
|
3384
|
+
ignore
|
|
3385
|
+
);
|
|
3386
|
+
}
|
|
3387
|
+
}
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3297
3390
|
})
|
|
3298
3391
|
});
|
|
3299
3392
|
|
|
@@ -3301,11 +3394,9 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
3301
3394
|
var unnecessaryEffectGen = createDiagnostic({
|
|
3302
3395
|
name: "unnecessaryEffectGen",
|
|
3303
3396
|
code: 5,
|
|
3304
|
-
apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile) {
|
|
3397
|
+
apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile, report) {
|
|
3305
3398
|
const ts = yield* service(TypeScriptApi);
|
|
3306
3399
|
const typeParser = yield* service(TypeParser);
|
|
3307
|
-
const effectDiagnostics = [];
|
|
3308
|
-
const unnecessaryGenerators = /* @__PURE__ */ new Map();
|
|
3309
3400
|
const nodeToVisit = [];
|
|
3310
3401
|
const appendNodeToVisit = (node) => {
|
|
3311
3402
|
nodeToVisit.push(node);
|
|
@@ -3318,29 +3409,27 @@ var unnecessaryEffectGen = createDiagnostic({
|
|
|
3318
3409
|
if (ts.isCallExpression(node)) {
|
|
3319
3410
|
yield* pipe(
|
|
3320
3411
|
typeParser.unnecessaryEffectGen(node),
|
|
3321
|
-
map4(
|
|
3412
|
+
map4(
|
|
3413
|
+
({ replacementNode }) => report({
|
|
3414
|
+
node,
|
|
3415
|
+
category: ts.DiagnosticCategory.Suggestion,
|
|
3416
|
+
messageText: `This Effect.gen contains a single return statement.`,
|
|
3417
|
+
fixes: [{
|
|
3418
|
+
fixName: "unnecessaryEffectGen_fix",
|
|
3419
|
+
description: "Remove the Effect.gen, and keep the body",
|
|
3420
|
+
apply: gen2(function* () {
|
|
3421
|
+
const textChanges = yield* service(
|
|
3422
|
+
ChangeTracker
|
|
3423
|
+
);
|
|
3424
|
+
textChanges.replaceNode(sourceFile, node, yield* replacementNode);
|
|
3425
|
+
})
|
|
3426
|
+
}]
|
|
3427
|
+
})
|
|
3428
|
+
),
|
|
3322
3429
|
ignore
|
|
3323
3430
|
);
|
|
3324
3431
|
}
|
|
3325
3432
|
}
|
|
3326
|
-
unnecessaryGenerators.forEach(
|
|
3327
|
-
(yieldedResult, effectGenCall) => effectDiagnostics.push({
|
|
3328
|
-
node: effectGenCall,
|
|
3329
|
-
category: ts.DiagnosticCategory.Suggestion,
|
|
3330
|
-
messageText: `This Effect.gen contains a single return statement.`,
|
|
3331
|
-
fixes: [{
|
|
3332
|
-
fixName: "unnecessaryEffectGen_fix",
|
|
3333
|
-
description: "Remove the Effect.gen, and keep the body",
|
|
3334
|
-
apply: gen2(function* () {
|
|
3335
|
-
const textChanges = yield* service(
|
|
3336
|
-
ChangeTracker
|
|
3337
|
-
);
|
|
3338
|
-
textChanges.replaceNode(sourceFile, effectGenCall, yield* yieldedResult);
|
|
3339
|
-
})
|
|
3340
|
-
}]
|
|
3341
|
-
})
|
|
3342
|
-
);
|
|
3343
|
-
return effectDiagnostics;
|
|
3344
3433
|
})
|
|
3345
3434
|
});
|
|
3346
3435
|
|
|
@@ -3348,11 +3437,9 @@ var unnecessaryEffectGen = createDiagnostic({
|
|
|
3348
3437
|
var unnecessaryPipe = createDiagnostic({
|
|
3349
3438
|
name: "unnecessaryPipe",
|
|
3350
3439
|
code: 9,
|
|
3351
|
-
apply: fn("unnecessaryPipe.apply")(function* (sourceFile) {
|
|
3440
|
+
apply: fn("unnecessaryPipe.apply")(function* (sourceFile, report) {
|
|
3352
3441
|
const ts = yield* service(TypeScriptApi);
|
|
3353
3442
|
const typeParser = yield* service(TypeParser);
|
|
3354
|
-
const pipeDiagnostics = [];
|
|
3355
|
-
const unnecessaryPipes = /* @__PURE__ */ new Map();
|
|
3356
3443
|
const nodeToVisit = [];
|
|
3357
3444
|
const appendNodeToVisit = (node) => {
|
|
3358
3445
|
nodeToVisit.push(node);
|
|
@@ -3365,29 +3452,29 @@ var unnecessaryPipe = createDiagnostic({
|
|
|
3365
3452
|
if (ts.isCallExpression(node)) {
|
|
3366
3453
|
yield* pipe(
|
|
3367
3454
|
typeParser.pipeCall(node),
|
|
3368
|
-
map4(({ args, subject }) =>
|
|
3455
|
+
map4(({ args, subject }) => {
|
|
3456
|
+
if (args.length === 0) {
|
|
3457
|
+
report({
|
|
3458
|
+
node,
|
|
3459
|
+
category: ts.DiagnosticCategory.Suggestion,
|
|
3460
|
+
messageText: `This pipe call contains no arguments.`,
|
|
3461
|
+
fixes: [{
|
|
3462
|
+
fixName: "unnecessaryPipe_fix",
|
|
3463
|
+
description: "Remove the pipe call",
|
|
3464
|
+
apply: gen2(function* () {
|
|
3465
|
+
const textChanges = yield* service(
|
|
3466
|
+
ChangeTracker
|
|
3467
|
+
);
|
|
3468
|
+
textChanges.replaceNode(sourceFile, node, subject);
|
|
3469
|
+
})
|
|
3470
|
+
}]
|
|
3471
|
+
});
|
|
3472
|
+
}
|
|
3473
|
+
}),
|
|
3369
3474
|
ignore
|
|
3370
3475
|
);
|
|
3371
3476
|
}
|
|
3372
3477
|
}
|
|
3373
|
-
unnecessaryPipes.forEach(
|
|
3374
|
-
(pipeCall, pipeSubject) => pipeDiagnostics.push({
|
|
3375
|
-
node: pipeCall,
|
|
3376
|
-
category: ts.DiagnosticCategory.Suggestion,
|
|
3377
|
-
messageText: `This pipe call contains no arguments.`,
|
|
3378
|
-
fixes: [{
|
|
3379
|
-
fixName: "unnecessaryPipe_fix",
|
|
3380
|
-
description: "Remove the pipe call",
|
|
3381
|
-
apply: gen2(function* () {
|
|
3382
|
-
const textChanges = yield* service(
|
|
3383
|
-
ChangeTracker
|
|
3384
|
-
);
|
|
3385
|
-
textChanges.replaceNode(sourceFile, pipeSubject, pipeCall);
|
|
3386
|
-
})
|
|
3387
|
-
}]
|
|
3388
|
-
})
|
|
3389
|
-
);
|
|
3390
|
-
return pipeDiagnostics;
|
|
3391
3478
|
})
|
|
3392
3479
|
});
|
|
3393
3480
|
|
|
@@ -3401,7 +3488,9 @@ var diagnostics = [
|
|
|
3401
3488
|
unnecessaryEffectGen,
|
|
3402
3489
|
missingReturnYieldStar,
|
|
3403
3490
|
leakingRequirements,
|
|
3404
|
-
unnecessaryPipe
|
|
3491
|
+
unnecessaryPipe,
|
|
3492
|
+
genericEffectServices,
|
|
3493
|
+
returnEffectInGen
|
|
3405
3494
|
];
|
|
3406
3495
|
|
|
3407
3496
|
// src/goto/effectRpcDefinition.ts
|