@effect/language-service 0.38.4 → 0.40.0

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 CHANGED
@@ -55,6 +55,7 @@ And you're done! You'll now be able to use a set of refactors and diagnostics th
55
55
  - Warn on subsequent `Effect.provide` anti-pattern
56
56
  - Detect wrong `Self` type parameter for APIs like `Effect.Service` or `Schema.TaggedError` and similar 
57
57
  - Unnecessary usages of `Effect.gen` or `pipe()`
58
+ - Warn when using `Effect.gen` with the old generator adapter pattern
58
59
  - Warn when importing from a barrel file instead of from the module directly
59
60
  - Warn on usage of try/catch inside `Effect.gen` and family
60
61
  - Detect unnecessary pipe chains like `X.pipe(Y).pipe(Z)`
@@ -116,7 +117,8 @@ Few options can be provided alongside the initialization of the Language Service
116
117
  "barrelImportPackages": [], // package names that should be preferred as imported from the top level barrel file (default: [])
117
118
  "namespaceImportPackages": [], // package names that should be preferred as imported with namespace imports e.g. ["effect", "@effect/*"] (default: [])
118
119
  "topLevelNamedReexports": "ignore", // for namespaceImportPackages, how should top level named re-exports (e.g. {pipe} from "effect") be treated? "ignore" will leave them as is, "follow" will rewrite them to the re-exported module (e.g. {pipe} from "effect/Function")
119
- "importAliases": { "Array": "Arr" } // allows to chose some different names for import name aliases (only when not chosing to import the whole module) (default: {})
120
+ "importAliases": { "Array": "Arr" }, // allows to chose some different names for import name aliases (only when not chosing to import the whole module) (default: {})
121
+ "noExternal": false // disables features that provides links to external websites (such as links to mermaidchart.com) (default: false)
120
122
  }
121
123
  ]
122
124
  }
@@ -1182,7 +1182,8 @@ var defaults = {
1182
1182
  topLevelNamedReexports: "ignore",
1183
1183
  barrelImportPackages: [],
1184
1184
  importAliases: {},
1185
- renames: true
1185
+ renames: true,
1186
+ noExternal: false
1186
1187
  };
1187
1188
  function parse(config) {
1188
1189
  return {
@@ -1199,7 +1200,8 @@ function parse(config) {
1199
1200
  barrelImportPackages: isObject(config) && hasProperty(config, "barrelImportPackages") && isArray(config.barrelImportPackages) && config.barrelImportPackages.every(isString) ? config.barrelImportPackages.map((_) => _.toLowerCase()) : defaults.barrelImportPackages,
1200
1201
  importAliases: isObject(config) && hasProperty(config, "importAliases") && isRecord(config.importAliases) ? map2(config.importAliases, (value) => String(value)) : defaults.importAliases,
1201
1202
  topLevelNamedReexports: isObject(config) && hasProperty(config, "topLevelNamedReexports") && isString(config.topLevelNamedReexports) && ["ignore", "follow"].includes(config.topLevelNamedReexports.toLowerCase()) ? config.topLevelNamedReexports.toLowerCase() : defaults.topLevelNamedReexports,
1202
- renames: isObject(config) && hasProperty(config, "renames") && isBoolean(config.renames) ? config.renames : defaults.renames
1203
+ renames: isObject(config) && hasProperty(config, "renames") && isBoolean(config.renames) ? config.renames : defaults.renames,
1204
+ noExternal: isObject(config) && hasProperty(config, "noExternal") && isBoolean(config.noExternal) ? config.noExternal : defaults.noExternal
1203
1205
  };
1204
1206
  }
1205
1207
 
@@ -2462,13 +2464,28 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
2462
2464
  );
2463
2465
  const importedSchemaModule = cachedBy(
2464
2466
  fn("TypeParser.importedSchemaModule")(function* (node) {
2467
+ if (!ts.isIdentifier(node)) {
2468
+ return yield* typeParserIssue("Node is not an expression", void 0, node);
2469
+ }
2465
2470
  const type = typeChecker.getTypeAtLocation(node);
2466
2471
  const propertySymbol = typeChecker.getPropertyOfType(type, "Class");
2467
2472
  if (!propertySymbol) {
2468
2473
  return yield* typeParserIssue("Type has no 'Class' property", type, node);
2469
2474
  }
2470
- if (!ts.isExpression(node)) {
2471
- return yield* typeParserIssue("Node is not an expression", type, node);
2475
+ const sourceFile = tsUtils.getSourceFileOfNode(node);
2476
+ if (!sourceFile) {
2477
+ return yield* typeParserIssue("Node is not in a source file", void 0, node);
2478
+ }
2479
+ const schemaIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
2480
+ sourceFile,
2481
+ "effect",
2482
+ "Schema"
2483
+ );
2484
+ if (!schemaIdentifier) {
2485
+ return yield* typeParserIssue("Schema module not found", void 0, node);
2486
+ }
2487
+ if (ts.idText(node) !== schemaIdentifier) {
2488
+ return yield* typeParserIssue("Node is not a schema module reference", void 0, node);
2472
2489
  }
2473
2490
  return node;
2474
2491
  }),
@@ -2482,8 +2499,23 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
2482
2499
  if (!propertySymbol) {
2483
2500
  return yield* typeParserIssue("Type has no 'Tag' property", type, node);
2484
2501
  }
2485
- if (!ts.isExpression(node)) {
2486
- return yield* typeParserIssue("Node is not an expression", type, node);
2502
+ if (!ts.isIdentifier(node)) {
2503
+ return yield* typeParserIssue("Node is not an identifier", type, node);
2504
+ }
2505
+ const sourceFile = tsUtils.getSourceFileOfNode(node);
2506
+ if (!sourceFile) {
2507
+ return yield* typeParserIssue("Node is not in a source file", void 0, node);
2508
+ }
2509
+ const contextIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
2510
+ sourceFile,
2511
+ "effect",
2512
+ "Context"
2513
+ );
2514
+ if (!contextIdentifier) {
2515
+ return yield* typeParserIssue("Context module not found", void 0, node);
2516
+ }
2517
+ if (ts.idText(node) !== contextIdentifier) {
2518
+ return yield* typeParserIssue("Node is not a context module reference", void 0, node);
2487
2519
  }
2488
2520
  return node;
2489
2521
  }),
@@ -2514,9 +2546,24 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
2514
2546
  if (!propertySymbol) {
2515
2547
  return yield* typeParserIssue("Type has no 'TaggedError' property", type, node);
2516
2548
  }
2517
- if (!ts.isExpression(node)) {
2549
+ if (!ts.isIdentifier(node)) {
2518
2550
  return yield* typeParserIssue("Node is not an expression", type, node);
2519
2551
  }
2552
+ const sourceFile = tsUtils.getSourceFileOfNode(node);
2553
+ if (!sourceFile) {
2554
+ return yield* typeParserIssue("Node is not in a source file", void 0, node);
2555
+ }
2556
+ const dataIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
2557
+ sourceFile,
2558
+ "effect",
2559
+ "Data"
2560
+ );
2561
+ if (!dataIdentifier) {
2562
+ return yield* typeParserIssue("Data module not found", void 0, node);
2563
+ }
2564
+ if (ts.idText(node) !== dataIdentifier) {
2565
+ return yield* typeParserIssue("Node is not a data module reference", void 0, node);
2566
+ }
2520
2567
  return node;
2521
2568
  }),
2522
2569
  "TypeParser.importedDataModule",
@@ -2879,8 +2926,10 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
2879
2926
  const selfTypeNode = schemaCall.typeArguments[0];
2880
2927
  const schemaIdentifier = schemaCall.expression;
2881
2928
  if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "Class") {
2929
+ const expressionType = typeChecker.getTypeAtLocation(expression);
2882
2930
  const parsedSchemaModule = yield* pipe(
2883
- importedSchemaModule(schemaIdentifier.expression),
2931
+ effectSchemaType(expressionType, expression),
2932
+ flatMap2(() => importedSchemaModule(schemaIdentifier.expression)),
2884
2933
  option
2885
2934
  );
2886
2935
  if (isSome2(parsedSchemaModule)) {
@@ -2920,8 +2969,10 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
2920
2969
  const selfTypeNode = schemaTaggedClassTCall.typeArguments[0];
2921
2970
  const schemaIdentifier = schemaTaggedClassTCall.expression;
2922
2971
  if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "TaggedClass") {
2972
+ const expressionType = typeChecker.getTypeAtLocation(expression);
2923
2973
  const parsedSchemaModule = yield* pipe(
2924
- importedSchemaModule(schemaIdentifier.expression),
2974
+ effectSchemaType(expressionType, expression),
2975
+ flatMap2(() => importedSchemaModule(schemaIdentifier.expression)),
2925
2976
  option
2926
2977
  );
2927
2978
  if (isSome2(parsedSchemaModule)) {
@@ -2963,8 +3014,10 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
2963
3014
  const selfTypeNode = schemaTaggedErrorTCall.typeArguments[0];
2964
3015
  const schemaIdentifier = schemaTaggedErrorTCall.expression;
2965
3016
  if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "TaggedError") {
3017
+ const expressionType = typeChecker.getTypeAtLocation(expression);
2966
3018
  const parsedSchemaModule = yield* pipe(
2967
- importedSchemaModule(schemaIdentifier.expression),
3019
+ effectSchemaType(expressionType, expression),
3020
+ flatMap2(() => importedSchemaModule(schemaIdentifier.expression)),
2968
3021
  option
2969
3022
  );
2970
3023
  if (isSome2(parsedSchemaModule)) {
@@ -3082,8 +3135,10 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3082
3135
  const selfTypeNode = schemaTaggedRequestTCall.typeArguments[0];
3083
3136
  const schemaIdentifier = schemaTaggedRequestTCall.expression;
3084
3137
  if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "TaggedRequest") {
3138
+ const expressionType = typeChecker.getTypeAtLocation(expression);
3085
3139
  const parsedSchemaModule = yield* pipe(
3086
- importedSchemaModule(schemaIdentifier.expression),
3140
+ effectSchemaType(expressionType, expression),
3141
+ flatMap2(() => importedSchemaModule(schemaIdentifier.expression)),
3087
3142
  option
3088
3143
  );
3089
3144
  if (isSome2(parsedSchemaModule)) {
@@ -3317,6 +3372,7 @@ var classSelfMismatch = createDiagnostic({
3317
3372
  const result = yield* pipe(
3318
3373
  typeParser.extendsEffectService(node),
3319
3374
  orElse2(() => typeParser.extendsContextTag(node)),
3375
+ orElse2(() => typeParser.extendsEffectTag(node)),
3320
3376
  orElse2(() => typeParser.extendsSchemaClass(node)),
3321
3377
  orElse2(() => typeParser.extendsSchemaTaggedClass(node)),
3322
3378
  orElse2(() => typeParser.extendsSchemaTaggedError(node)),
@@ -3409,6 +3465,43 @@ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageNam
3409
3465
  })
3410
3466
  });
3411
3467
 
3468
+ // src/diagnostics/effectGenUsesAdapter.ts
3469
+ var effectGenUsesAdapter = createDiagnostic({
3470
+ name: "effectGenUsesAdapter",
3471
+ code: 23,
3472
+ severity: "warning",
3473
+ apply: fn("effectGenUsesAdapter.apply")(function* (sourceFile, report) {
3474
+ const ts = yield* service(TypeScriptApi);
3475
+ const typeParser = yield* service(TypeParser);
3476
+ const nodeToVisit = [];
3477
+ const appendNodeToVisit = (node) => {
3478
+ nodeToVisit.push(node);
3479
+ return void 0;
3480
+ };
3481
+ ts.forEachChild(sourceFile, appendNodeToVisit);
3482
+ while (nodeToVisit.length > 0) {
3483
+ const node = nodeToVisit.shift();
3484
+ ts.forEachChild(node, appendNodeToVisit);
3485
+ if (ts.isCallExpression(node)) {
3486
+ yield* pipe(
3487
+ typeParser.effectGen(node),
3488
+ map4(({ generatorFunction }) => {
3489
+ if (generatorFunction.parameters.length > 0) {
3490
+ const adapter = generatorFunction.parameters[0];
3491
+ report({
3492
+ location: adapter,
3493
+ messageText: `The adapter of Effect.gen is not required anymore, it is now just an alias of pipe.`,
3494
+ fixes: []
3495
+ });
3496
+ }
3497
+ }),
3498
+ ignore
3499
+ );
3500
+ }
3501
+ }
3502
+ })
3503
+ });
3504
+
3412
3505
  // src/diagnostics/effectInVoidSuccess.ts
3413
3506
  var effectInVoidSuccess = createDiagnostic({
3414
3507
  name: "effectInVoidSuccess",
@@ -5217,6 +5310,7 @@ var unsupportedServiceAccessors = createDiagnostic({
5217
5310
  var diagnostics = [
5218
5311
  classSelfMismatch,
5219
5312
  duplicatePackage,
5313
+ effectGenUsesAdapter,
5220
5314
  missingEffectContext,
5221
5315
  missingEffectError,
5222
5316
  missingEffectServiceDependency,