@effect/language-service 0.21.0 → 0.21.2
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 +4 -1
- package/index.js +194 -113
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +172 -96
- package/transform.js.map +1 -1
package/package.json
CHANGED
package/transform.js
CHANGED
|
@@ -144,6 +144,7 @@ var isFunction2 = isFunction;
|
|
|
144
144
|
var isRecordOrArray = (input) => typeof input === "object" && input !== null;
|
|
145
145
|
var isObject = (input) => isRecordOrArray(input) || isFunction2(input);
|
|
146
146
|
var hasProperty = /* @__PURE__ */ dual(2, (self, property) => isObject(self) && property in self);
|
|
147
|
+
var isRecord = (input) => isRecordOrArray(input) && !Array.isArray(input);
|
|
147
148
|
|
|
148
149
|
// node_modules/.pnpm/effect@3.16.5/node_modules/effect/dist/esm/internal/errors.js
|
|
149
150
|
var getBugErrorMessage = (message) => `BUG: ${message} - please report an issue at https://github.com/Effect-TS/effect/issues`;
|
|
@@ -975,9 +976,23 @@ function cachedBy(fa, key, lookupKey) {
|
|
|
975
976
|
|
|
976
977
|
// src/core/LanguageServicePluginOptions.ts
|
|
977
978
|
var LanguageServicePluginOptions = Tag("PluginOptions");
|
|
979
|
+
function parseDiagnosticSeverity(config) {
|
|
980
|
+
if (!isRecord(config)) return {};
|
|
981
|
+
return Object.fromEntries(
|
|
982
|
+
pipe(
|
|
983
|
+
Object.entries(config),
|
|
984
|
+
filter(([key, value]) => isString(key) && isString(value)),
|
|
985
|
+
map2(([key, value]) => [String(key).toLowerCase(), String(value).toLowerCase()]),
|
|
986
|
+
filter(
|
|
987
|
+
([_, value]) => value === "off" || value === "error" || value === "warning" || value === "message" || value === "suggestion"
|
|
988
|
+
)
|
|
989
|
+
)
|
|
990
|
+
);
|
|
991
|
+
}
|
|
978
992
|
function parse(config) {
|
|
979
993
|
return {
|
|
980
994
|
diagnostics: isObject(config) && hasProperty(config, "diagnostics") && isBoolean(config.diagnostics) ? config.diagnostics : true,
|
|
995
|
+
diagnosticSeverity: isObject(config) && hasProperty(config, "diagnosticSeverity") && isRecord(config.diagnosticSeverity) ? parseDiagnosticSeverity(config.diagnosticSeverity) : {},
|
|
981
996
|
quickinfo: isObject(config) && hasProperty(config, "quickinfo") && isBoolean(config.quickinfo) ? config.quickinfo : true,
|
|
982
997
|
completions: isObject(config) && hasProperty(config, "completions") && isBoolean(config.completions) ? config.completions : true,
|
|
983
998
|
goto: isObject(config) && hasProperty(config, "goto") && isBoolean(config.goto) ? config.goto : true,
|
|
@@ -1108,6 +1123,7 @@ var getCompletionsAtPosition = fn("LSP.getCompletionsAtPosition")(function* (com
|
|
|
1108
1123
|
var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
|
|
1109
1124
|
function* (sourceFile) {
|
|
1110
1125
|
const ts = yield* service(TypeScriptApi);
|
|
1126
|
+
const pluginOptions = yield* service(LanguageServicePluginOptions);
|
|
1111
1127
|
function findNodeWithLeadingCommentAtPosition(position) {
|
|
1112
1128
|
const sourceText = sourceFile.text;
|
|
1113
1129
|
let result;
|
|
@@ -1191,24 +1207,30 @@ var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
|
|
|
1191
1207
|
const ruleNameLowered = rule.name.toLowerCase();
|
|
1192
1208
|
if (skippedRules.indexOf(ruleNameLowered) > -1) return [];
|
|
1193
1209
|
let modifiedDiagnostics = yield* rule.apply(sourceFile);
|
|
1210
|
+
const newLevel = pluginOptions.diagnosticSeverity[ruleNameLowered];
|
|
1211
|
+
if (newLevel) {
|
|
1212
|
+
for (const emitted of modifiedDiagnostics) {
|
|
1213
|
+
emitted.category = newLevel && newLevel in levelToDiagnosticCategory ? levelToDiagnosticCategory[newLevel] : emitted.category;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1194
1216
|
for (const emitted of modifiedDiagnostics.slice(0)) {
|
|
1195
|
-
let
|
|
1217
|
+
let newLevel2 = void 0;
|
|
1196
1218
|
if (!(ruleNameLowered in sectionOverrides || ruleNameLowered in lineOverrides)) continue;
|
|
1197
1219
|
const lineOverride = (lineOverrides[ruleNameLowered] || []).find(
|
|
1198
1220
|
(_) => _.pos < emitted.node.getStart(sourceFile) && _.end >= emitted.node.getEnd()
|
|
1199
1221
|
);
|
|
1200
1222
|
if (lineOverride) {
|
|
1201
|
-
|
|
1223
|
+
newLevel2 = lineOverride.level;
|
|
1202
1224
|
} else {
|
|
1203
1225
|
const sectionOverride = (sectionOverrides[ruleNameLowered] || []).find(
|
|
1204
1226
|
(_) => _.pos < emitted.node.getStart(sourceFile)
|
|
1205
1227
|
);
|
|
1206
|
-
if (sectionOverride)
|
|
1228
|
+
if (sectionOverride) newLevel2 = sectionOverride.level;
|
|
1207
1229
|
}
|
|
1208
|
-
if (
|
|
1230
|
+
if (newLevel2 === "off") {
|
|
1209
1231
|
modifiedDiagnostics = modifiedDiagnostics.filter((_) => _ !== emitted);
|
|
1210
1232
|
} else {
|
|
1211
|
-
emitted.category =
|
|
1233
|
+
emitted.category = newLevel2 && newLevel2 in levelToDiagnosticCategory ? levelToDiagnosticCategory[newLevel2] : emitted.category;
|
|
1212
1234
|
}
|
|
1213
1235
|
}
|
|
1214
1236
|
const fixByDisableNextLine = (_) => ({
|
|
@@ -1845,19 +1867,6 @@ var createReturnYieldStarStatement = fn("AST.createReturnYieldStarStatement")(
|
|
|
1845
1867
|
);
|
|
1846
1868
|
}
|
|
1847
1869
|
);
|
|
1848
|
-
var parsePipeCall = fn("AST.parsePipeCall")(
|
|
1849
|
-
function* (node) {
|
|
1850
|
-
const ts = yield* service(TypeScriptApi);
|
|
1851
|
-
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) && node.expression.name.text === "pipe") {
|
|
1852
|
-
return { node, subject: node.expression.expression, args: node.arguments };
|
|
1853
|
-
}
|
|
1854
|
-
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "pipe" && node.arguments.length > 0) {
|
|
1855
|
-
const [subject, ...args] = node.arguments;
|
|
1856
|
-
return { node, subject, args };
|
|
1857
|
-
}
|
|
1858
|
-
return yield* fail(new NodeNotFoundError());
|
|
1859
|
-
}
|
|
1860
|
-
);
|
|
1861
1870
|
|
|
1862
1871
|
// src/core/TypeParser.ts
|
|
1863
1872
|
var TypeParser = Tag("@effect/language-service/TypeParser");
|
|
@@ -1891,18 +1900,18 @@ function make3(ts, typeChecker) {
|
|
|
1891
1900
|
return succeed(signatures[0].getReturnType());
|
|
1892
1901
|
}
|
|
1893
1902
|
const pipeableType = cachedBy(
|
|
1894
|
-
|
|
1903
|
+
function(type, atLocation) {
|
|
1895
1904
|
const pipeSymbol = typeChecker.getPropertyOfType(type, "pipe");
|
|
1896
1905
|
if (!pipeSymbol) {
|
|
1897
|
-
return
|
|
1906
|
+
return typeParserIssue("Type has no 'pipe' property", type, atLocation);
|
|
1898
1907
|
}
|
|
1899
1908
|
const pipeType = typeChecker.getTypeOfSymbolAtLocation(pipeSymbol, atLocation);
|
|
1900
1909
|
const signatures = pipeType.getCallSignatures();
|
|
1901
1910
|
if (signatures.length === 0) {
|
|
1902
|
-
return
|
|
1911
|
+
return typeParserIssue("'pipe' property is not callable", type, atLocation);
|
|
1903
1912
|
}
|
|
1904
|
-
return type;
|
|
1905
|
-
}
|
|
1913
|
+
return succeed(type);
|
|
1914
|
+
},
|
|
1906
1915
|
"TypeParser.pipeableType",
|
|
1907
1916
|
(type) => type
|
|
1908
1917
|
);
|
|
@@ -2040,105 +2049,107 @@ function make3(ts, typeChecker) {
|
|
|
2040
2049
|
(node) => node
|
|
2041
2050
|
);
|
|
2042
2051
|
const effectGen = cachedBy(
|
|
2043
|
-
|
|
2052
|
+
function(node) {
|
|
2044
2053
|
if (!ts.isCallExpression(node)) {
|
|
2045
|
-
return
|
|
2054
|
+
return typeParserIssue("Node is not a call expression", void 0, node);
|
|
2046
2055
|
}
|
|
2047
2056
|
if (node.arguments.length === 0) {
|
|
2048
|
-
return
|
|
2057
|
+
return typeParserIssue("Node has no arguments", void 0, node);
|
|
2049
2058
|
}
|
|
2050
2059
|
const generatorFunction = node.arguments[0];
|
|
2051
2060
|
if (!ts.isFunctionExpression(generatorFunction)) {
|
|
2052
|
-
return
|
|
2061
|
+
return typeParserIssue("Node is not a function expression", void 0, node);
|
|
2053
2062
|
}
|
|
2054
2063
|
if (generatorFunction.asteriskToken === void 0) {
|
|
2055
|
-
return
|
|
2064
|
+
return typeParserIssue("Node is not a generator function", void 0, node);
|
|
2056
2065
|
}
|
|
2057
2066
|
if (!ts.isPropertyAccessExpression(node.expression)) {
|
|
2058
|
-
return
|
|
2067
|
+
return typeParserIssue("Node is not a property access expression", void 0, node);
|
|
2059
2068
|
}
|
|
2060
2069
|
const propertyAccess = node.expression;
|
|
2061
2070
|
if (propertyAccess.name.text !== "gen") {
|
|
2062
|
-
return
|
|
2071
|
+
return typeParserIssue("Call expression name is not 'gen'", void 0, node);
|
|
2063
2072
|
}
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
+
return pipe(
|
|
2074
|
+
importedEffectModule(propertyAccess.expression),
|
|
2075
|
+
map3((effectModule) => ({
|
|
2076
|
+
node,
|
|
2077
|
+
effectModule,
|
|
2078
|
+
generatorFunction,
|
|
2079
|
+
body: generatorFunction.body,
|
|
2080
|
+
functionStar: generatorFunction.getFirstToken()
|
|
2081
|
+
}))
|
|
2082
|
+
);
|
|
2083
|
+
},
|
|
2073
2084
|
"TypeParser.effectGen",
|
|
2074
2085
|
(node) => node
|
|
2075
2086
|
);
|
|
2076
2087
|
const effectFnUntracedGen = cachedBy(
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2088
|
+
function(node) {
|
|
2089
|
+
if (!ts.isCallExpression(node)) {
|
|
2090
|
+
return typeParserIssue("Node is not a call expression", void 0, node);
|
|
2091
|
+
}
|
|
2092
|
+
if (node.arguments.length === 0) {
|
|
2093
|
+
return typeParserIssue("Node has no arguments", void 0, node);
|
|
2094
|
+
}
|
|
2095
|
+
const generatorFunction = node.arguments[0];
|
|
2096
|
+
if (!ts.isFunctionExpression(generatorFunction)) {
|
|
2097
|
+
return typeParserIssue("Node is not a function expression", void 0, node);
|
|
2098
|
+
}
|
|
2099
|
+
if (generatorFunction.asteriskToken === void 0) {
|
|
2100
|
+
return typeParserIssue(
|
|
2101
|
+
"Node is not a generator function",
|
|
2102
|
+
void 0,
|
|
2103
|
+
node
|
|
2104
|
+
);
|
|
2105
|
+
}
|
|
2106
|
+
if (!ts.isPropertyAccessExpression(node.expression)) {
|
|
2107
|
+
return typeParserIssue(
|
|
2108
|
+
"Node is not a property access expression",
|
|
2109
|
+
void 0,
|
|
2110
|
+
node
|
|
2111
|
+
);
|
|
2112
|
+
}
|
|
2113
|
+
const propertyAccess = node.expression;
|
|
2114
|
+
if (propertyAccess.name.text !== "fnUntraced") {
|
|
2115
|
+
return typeParserIssue(
|
|
2116
|
+
"Call expression name is not 'fnUntraced'",
|
|
2117
|
+
void 0,
|
|
2118
|
+
node
|
|
2119
|
+
);
|
|
2120
|
+
}
|
|
2121
|
+
return pipe(
|
|
2122
|
+
importedEffectModule(propertyAccess.expression),
|
|
2123
|
+
map3((effectModule) => ({
|
|
2113
2124
|
node,
|
|
2114
2125
|
effectModule,
|
|
2115
2126
|
generatorFunction,
|
|
2116
2127
|
body: generatorFunction.body,
|
|
2117
2128
|
functionStar: generatorFunction.getFirstToken()
|
|
2118
|
-
}
|
|
2119
|
-
|
|
2120
|
-
|
|
2129
|
+
}))
|
|
2130
|
+
);
|
|
2131
|
+
},
|
|
2121
2132
|
"TypeParser.effectFnUntracedGen",
|
|
2122
2133
|
(node) => node
|
|
2123
2134
|
);
|
|
2124
2135
|
const effectFnGen = cachedBy(
|
|
2125
|
-
|
|
2136
|
+
function(node) {
|
|
2126
2137
|
if (!ts.isCallExpression(node)) {
|
|
2127
|
-
return
|
|
2138
|
+
return typeParserIssue("Node is not a call expression", void 0, node);
|
|
2128
2139
|
}
|
|
2129
2140
|
if (node.arguments.length === 0) {
|
|
2130
|
-
return
|
|
2141
|
+
return typeParserIssue("Node has no arguments", void 0, node);
|
|
2131
2142
|
}
|
|
2132
2143
|
const generatorFunction = node.arguments[0];
|
|
2133
2144
|
if (!ts.isFunctionExpression(generatorFunction)) {
|
|
2134
|
-
return
|
|
2145
|
+
return typeParserIssue(
|
|
2135
2146
|
"Node is not a function expression",
|
|
2136
2147
|
void 0,
|
|
2137
2148
|
node
|
|
2138
2149
|
);
|
|
2139
2150
|
}
|
|
2140
2151
|
if (generatorFunction.asteriskToken === void 0) {
|
|
2141
|
-
return
|
|
2152
|
+
return typeParserIssue(
|
|
2142
2153
|
"Node is not a generator function",
|
|
2143
2154
|
void 0,
|
|
2144
2155
|
node
|
|
@@ -2146,7 +2157,7 @@ function make3(ts, typeChecker) {
|
|
|
2146
2157
|
}
|
|
2147
2158
|
const expressionToTest = ts.isCallExpression(node.expression) ? node.expression.expression : node.expression;
|
|
2148
2159
|
if (!ts.isPropertyAccessExpression(expressionToTest)) {
|
|
2149
|
-
return
|
|
2160
|
+
return typeParserIssue(
|
|
2150
2161
|
"Node is not a property access expression",
|
|
2151
2162
|
void 0,
|
|
2152
2163
|
node
|
|
@@ -2154,21 +2165,23 @@ function make3(ts, typeChecker) {
|
|
|
2154
2165
|
}
|
|
2155
2166
|
const propertyAccess = expressionToTest;
|
|
2156
2167
|
if (propertyAccess.name.text !== "fn") {
|
|
2157
|
-
return
|
|
2168
|
+
return typeParserIssue(
|
|
2158
2169
|
"Call expression name is not 'fn'",
|
|
2159
2170
|
void 0,
|
|
2160
2171
|
node
|
|
2161
2172
|
);
|
|
2162
2173
|
}
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2174
|
+
return pipe(
|
|
2175
|
+
importedEffectModule(propertyAccess.expression),
|
|
2176
|
+
map3((effectModule) => ({
|
|
2177
|
+
node,
|
|
2178
|
+
generatorFunction,
|
|
2179
|
+
effectModule,
|
|
2180
|
+
body: generatorFunction.body,
|
|
2181
|
+
functionStar: generatorFunction.getFirstToken()
|
|
2182
|
+
}))
|
|
2183
|
+
);
|
|
2184
|
+
},
|
|
2172
2185
|
"TypeParser.effectFnGen",
|
|
2173
2186
|
(node) => node
|
|
2174
2187
|
);
|
|
@@ -2299,6 +2312,20 @@ function make3(ts, typeChecker) {
|
|
|
2299
2312
|
"TypeParser.contextTag",
|
|
2300
2313
|
(type) => type
|
|
2301
2314
|
);
|
|
2315
|
+
const pipeCall = cachedBy(
|
|
2316
|
+
function(node) {
|
|
2317
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) && node.expression.name.text === "pipe") {
|
|
2318
|
+
return succeed({ node, subject: node.expression.expression, args: Array.from(node.arguments) });
|
|
2319
|
+
}
|
|
2320
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "pipe" && node.arguments.length > 0) {
|
|
2321
|
+
const [subject, ...args] = node.arguments;
|
|
2322
|
+
return succeed({ node, subject, args });
|
|
2323
|
+
}
|
|
2324
|
+
return typeParserIssue("Node is not a pipe call", void 0, node);
|
|
2325
|
+
},
|
|
2326
|
+
"TypeParser.pipeCall",
|
|
2327
|
+
(node) => node
|
|
2328
|
+
);
|
|
2302
2329
|
return {
|
|
2303
2330
|
effectType,
|
|
2304
2331
|
layerType,
|
|
@@ -2310,7 +2337,8 @@ function make3(ts, typeChecker) {
|
|
|
2310
2337
|
effectFnGen,
|
|
2311
2338
|
unnecessaryEffectGen: unnecessaryEffectGen2,
|
|
2312
2339
|
effectSchemaType,
|
|
2313
|
-
contextTag
|
|
2340
|
+
contextTag,
|
|
2341
|
+
pipeCall
|
|
2314
2342
|
};
|
|
2315
2343
|
}
|
|
2316
2344
|
|
|
@@ -2816,6 +2844,53 @@ var unnecessaryEffectGen = createDiagnostic({
|
|
|
2816
2844
|
})
|
|
2817
2845
|
});
|
|
2818
2846
|
|
|
2847
|
+
// src/diagnostics/unnecessaryPipe.ts
|
|
2848
|
+
var unnecessaryPipe = createDiagnostic({
|
|
2849
|
+
name: "unnecessaryPipe",
|
|
2850
|
+
code: 9,
|
|
2851
|
+
apply: fn("unnecessaryPipe.apply")(function* (sourceFile) {
|
|
2852
|
+
const ts = yield* service(TypeScriptApi);
|
|
2853
|
+
const typeParser = yield* service(TypeParser);
|
|
2854
|
+
const pipeDiagnostics = [];
|
|
2855
|
+
const unnecessaryPipes = /* @__PURE__ */ new Map();
|
|
2856
|
+
const nodeToVisit = [];
|
|
2857
|
+
const appendNodeToVisit = (node) => {
|
|
2858
|
+
nodeToVisit.push(node);
|
|
2859
|
+
return void 0;
|
|
2860
|
+
};
|
|
2861
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
2862
|
+
while (nodeToVisit.length > 0) {
|
|
2863
|
+
const node = nodeToVisit.shift();
|
|
2864
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
2865
|
+
if (ts.isCallExpression(node)) {
|
|
2866
|
+
yield* pipe(
|
|
2867
|
+
typeParser.pipeCall(node),
|
|
2868
|
+
map3(({ args, subject }) => args.length === 0 ? unnecessaryPipes.set(node, subject) : void 0),
|
|
2869
|
+
ignore
|
|
2870
|
+
);
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
unnecessaryPipes.forEach(
|
|
2874
|
+
(pipeCall, pipeSubject) => pipeDiagnostics.push({
|
|
2875
|
+
node: pipeCall,
|
|
2876
|
+
category: ts.DiagnosticCategory.Suggestion,
|
|
2877
|
+
messageText: `This pipe call contains no arguments.`,
|
|
2878
|
+
fixes: [{
|
|
2879
|
+
fixName: "unnecessaryPipe_fix",
|
|
2880
|
+
description: "Remove the pipe call",
|
|
2881
|
+
apply: gen(function* () {
|
|
2882
|
+
const textChanges = yield* service(
|
|
2883
|
+
ChangeTracker
|
|
2884
|
+
);
|
|
2885
|
+
textChanges.replaceNode(sourceFile, pipeSubject, pipeCall);
|
|
2886
|
+
})
|
|
2887
|
+
}]
|
|
2888
|
+
})
|
|
2889
|
+
);
|
|
2890
|
+
return pipeDiagnostics;
|
|
2891
|
+
})
|
|
2892
|
+
});
|
|
2893
|
+
|
|
2819
2894
|
// src/diagnostics.ts
|
|
2820
2895
|
var diagnostics = [
|
|
2821
2896
|
duplicatePackage,
|
|
@@ -2825,7 +2900,8 @@ var diagnostics = [
|
|
|
2825
2900
|
missingStarInYieldEffectGen,
|
|
2826
2901
|
unnecessaryEffectGen,
|
|
2827
2902
|
missingReturnYieldStar,
|
|
2828
|
-
leakingRequirements
|
|
2903
|
+
leakingRequirements,
|
|
2904
|
+
unnecessaryPipe
|
|
2829
2905
|
];
|
|
2830
2906
|
|
|
2831
2907
|
// src/transform.ts
|