@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect/language-service",
3
- "version": "0.21.0",
3
+ "version": "0.21.2",
4
4
  "description": "A Language-Service Plugin to Refactor and Diagnostic effect-ts projects",
5
5
  "main": "index.cjs",
6
6
  "repository": {
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 newLevel = void 0;
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
- newLevel = lineOverride.level;
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) newLevel = sectionOverride.level;
1228
+ if (sectionOverride) newLevel2 = sectionOverride.level;
1207
1229
  }
1208
- if (newLevel === "off") {
1230
+ if (newLevel2 === "off") {
1209
1231
  modifiedDiagnostics = modifiedDiagnostics.filter((_) => _ !== emitted);
1210
1232
  } else {
1211
- emitted.category = newLevel && newLevel in levelToDiagnosticCategory ? levelToDiagnosticCategory[newLevel] : 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
- fn("TypeParser.pipeableType")(function* (type, atLocation) {
1903
+ function(type, atLocation) {
1895
1904
  const pipeSymbol = typeChecker.getPropertyOfType(type, "pipe");
1896
1905
  if (!pipeSymbol) {
1897
- return yield* typeParserIssue("Type has no 'pipe' property", type, atLocation);
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 yield* typeParserIssue("'pipe' property is not callable", type, atLocation);
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
- fn("TypeParser.effectGen")(function* (node) {
2052
+ function(node) {
2044
2053
  if (!ts.isCallExpression(node)) {
2045
- return yield* typeParserIssue("Node is not a call expression", void 0, node);
2054
+ return typeParserIssue("Node is not a call expression", void 0, node);
2046
2055
  }
2047
2056
  if (node.arguments.length === 0) {
2048
- return yield* typeParserIssue("Node has no arguments", void 0, node);
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 yield* typeParserIssue("Node is not a function expression", void 0, node);
2061
+ return typeParserIssue("Node is not a function expression", void 0, node);
2053
2062
  }
2054
2063
  if (generatorFunction.asteriskToken === void 0) {
2055
- return yield* typeParserIssue("Node is not a generator function", void 0, node);
2064
+ return typeParserIssue("Node is not a generator function", void 0, node);
2056
2065
  }
2057
2066
  if (!ts.isPropertyAccessExpression(node.expression)) {
2058
- return yield* typeParserIssue("Node is not a property access expression", void 0, node);
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 yield* typeParserIssue("Call expression name is not 'gen'", void 0, node);
2071
+ return typeParserIssue("Call expression name is not 'gen'", void 0, node);
2063
2072
  }
2064
- const effectModule = yield* importedEffectModule(propertyAccess.expression);
2065
- return {
2066
- node,
2067
- effectModule,
2068
- generatorFunction,
2069
- body: generatorFunction.body,
2070
- functionStar: generatorFunction.getFirstToken()
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
- fn("TypeParser.effectFnUntracedGen")(
2078
- function* (node) {
2079
- if (!ts.isCallExpression(node)) {
2080
- return yield* typeParserIssue("Node is not a call expression", void 0, node);
2081
- }
2082
- if (node.arguments.length === 0) {
2083
- return yield* typeParserIssue("Node has no arguments", void 0, node);
2084
- }
2085
- const generatorFunction = node.arguments[0];
2086
- if (!ts.isFunctionExpression(generatorFunction)) {
2087
- return yield* typeParserIssue("Node is not a function expression", void 0, node);
2088
- }
2089
- if (generatorFunction.asteriskToken === void 0) {
2090
- return yield* typeParserIssue(
2091
- "Node is not a generator function",
2092
- void 0,
2093
- node
2094
- );
2095
- }
2096
- if (!ts.isPropertyAccessExpression(node.expression)) {
2097
- return yield* typeParserIssue(
2098
- "Node is not a property access expression",
2099
- void 0,
2100
- node
2101
- );
2102
- }
2103
- const propertyAccess = node.expression;
2104
- if (propertyAccess.name.text !== "fnUntraced") {
2105
- return yield* typeParserIssue(
2106
- "Call expression name is not 'fnUntraced'",
2107
- void 0,
2108
- node
2109
- );
2110
- }
2111
- const effectModule = yield* importedEffectModule(propertyAccess.expression);
2112
- return {
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
- fn("TypeParser.effectFnGen")(function* (node) {
2136
+ function(node) {
2126
2137
  if (!ts.isCallExpression(node)) {
2127
- return yield* typeParserIssue("Node is not a call expression", void 0, node);
2138
+ return typeParserIssue("Node is not a call expression", void 0, node);
2128
2139
  }
2129
2140
  if (node.arguments.length === 0) {
2130
- return yield* typeParserIssue("Node has no arguments", void 0, node);
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 yield* typeParserIssue(
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 yield* typeParserIssue(
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 yield* typeParserIssue(
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 yield* typeParserIssue(
2168
+ return typeParserIssue(
2158
2169
  "Call expression name is not 'fn'",
2159
2170
  void 0,
2160
2171
  node
2161
2172
  );
2162
2173
  }
2163
- const effectModule = yield* importedEffectModule(propertyAccess.expression);
2164
- return {
2165
- node,
2166
- generatorFunction,
2167
- effectModule,
2168
- body: generatorFunction.body,
2169
- functionStar: generatorFunction.getFirstToken()
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