@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/index.js CHANGED
@@ -1701,7 +1701,8 @@ var defaults = {
1701
1701
  topLevelNamedReexports: "ignore",
1702
1702
  barrelImportPackages: [],
1703
1703
  importAliases: {},
1704
- renames: true
1704
+ renames: true,
1705
+ noExternal: false
1705
1706
  };
1706
1707
  function parse(config) {
1707
1708
  return {
@@ -1718,7 +1719,8 @@ function parse(config) {
1718
1719
  barrelImportPackages: isObject(config) && hasProperty(config, "barrelImportPackages") && isArray(config.barrelImportPackages) && config.barrelImportPackages.every(isString) ? config.barrelImportPackages.map((_) => _.toLowerCase()) : defaults.barrelImportPackages,
1719
1720
  importAliases: isObject(config) && hasProperty(config, "importAliases") && isRecord(config.importAliases) ? map4(config.importAliases, (value) => String(value)) : defaults.importAliases,
1720
1721
  topLevelNamedReexports: isObject(config) && hasProperty(config, "topLevelNamedReexports") && isString(config.topLevelNamedReexports) && ["ignore", "follow"].includes(config.topLevelNamedReexports.toLowerCase()) ? config.topLevelNamedReexports.toLowerCase() : defaults.topLevelNamedReexports,
1721
- renames: isObject(config) && hasProperty(config, "renames") && isBoolean(config.renames) ? config.renames : defaults.renames
1722
+ renames: isObject(config) && hasProperty(config, "renames") && isBoolean(config.renames) ? config.renames : defaults.renames,
1723
+ noExternal: isObject(config) && hasProperty(config, "noExternal") && isBoolean(config.noExternal) ? config.noExternal : defaults.noExternal
1722
1724
  };
1723
1725
  }
1724
1726
 
@@ -2561,13 +2563,28 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils) {
2561
2563
  );
2562
2564
  const importedSchemaModule = cachedBy(
2563
2565
  fn("TypeParser.importedSchemaModule")(function* (node) {
2566
+ if (!ts.isIdentifier(node)) {
2567
+ return yield* typeParserIssue("Node is not an expression", void 0, node);
2568
+ }
2564
2569
  const type = typeChecker.getTypeAtLocation(node);
2565
2570
  const propertySymbol = typeChecker.getPropertyOfType(type, "Class");
2566
2571
  if (!propertySymbol) {
2567
2572
  return yield* typeParserIssue("Type has no 'Class' property", type, node);
2568
2573
  }
2569
- if (!ts.isExpression(node)) {
2570
- return yield* typeParserIssue("Node is not an expression", type, node);
2574
+ const sourceFile = tsUtils.getSourceFileOfNode(node);
2575
+ if (!sourceFile) {
2576
+ return yield* typeParserIssue("Node is not in a source file", void 0, node);
2577
+ }
2578
+ const schemaIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
2579
+ sourceFile,
2580
+ "effect",
2581
+ "Schema"
2582
+ );
2583
+ if (!schemaIdentifier) {
2584
+ return yield* typeParserIssue("Schema module not found", void 0, node);
2585
+ }
2586
+ if (ts.idText(node) !== schemaIdentifier) {
2587
+ return yield* typeParserIssue("Node is not a schema module reference", void 0, node);
2571
2588
  }
2572
2589
  return node;
2573
2590
  }),
@@ -2581,8 +2598,23 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils) {
2581
2598
  if (!propertySymbol) {
2582
2599
  return yield* typeParserIssue("Type has no 'Tag' property", type, node);
2583
2600
  }
2584
- if (!ts.isExpression(node)) {
2585
- return yield* typeParserIssue("Node is not an expression", type, node);
2601
+ if (!ts.isIdentifier(node)) {
2602
+ return yield* typeParserIssue("Node is not an identifier", type, node);
2603
+ }
2604
+ const sourceFile = tsUtils.getSourceFileOfNode(node);
2605
+ if (!sourceFile) {
2606
+ return yield* typeParserIssue("Node is not in a source file", void 0, node);
2607
+ }
2608
+ const contextIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
2609
+ sourceFile,
2610
+ "effect",
2611
+ "Context"
2612
+ );
2613
+ if (!contextIdentifier) {
2614
+ return yield* typeParserIssue("Context module not found", void 0, node);
2615
+ }
2616
+ if (ts.idText(node) !== contextIdentifier) {
2617
+ return yield* typeParserIssue("Node is not a context module reference", void 0, node);
2586
2618
  }
2587
2619
  return node;
2588
2620
  }),
@@ -2613,9 +2645,24 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils) {
2613
2645
  if (!propertySymbol) {
2614
2646
  return yield* typeParserIssue("Type has no 'TaggedError' property", type, node);
2615
2647
  }
2616
- if (!ts.isExpression(node)) {
2648
+ if (!ts.isIdentifier(node)) {
2617
2649
  return yield* typeParserIssue("Node is not an expression", type, node);
2618
2650
  }
2651
+ const sourceFile = tsUtils.getSourceFileOfNode(node);
2652
+ if (!sourceFile) {
2653
+ return yield* typeParserIssue("Node is not in a source file", void 0, node);
2654
+ }
2655
+ const dataIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
2656
+ sourceFile,
2657
+ "effect",
2658
+ "Data"
2659
+ );
2660
+ if (!dataIdentifier) {
2661
+ return yield* typeParserIssue("Data module not found", void 0, node);
2662
+ }
2663
+ if (ts.idText(node) !== dataIdentifier) {
2664
+ return yield* typeParserIssue("Node is not a data module reference", void 0, node);
2665
+ }
2619
2666
  return node;
2620
2667
  }),
2621
2668
  "TypeParser.importedDataModule",
@@ -2978,8 +3025,10 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils) {
2978
3025
  const selfTypeNode = schemaCall.typeArguments[0];
2979
3026
  const schemaIdentifier = schemaCall.expression;
2980
3027
  if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "Class") {
3028
+ const expressionType = typeChecker.getTypeAtLocation(expression);
2981
3029
  const parsedSchemaModule = yield* pipe(
2982
- importedSchemaModule(schemaIdentifier.expression),
3030
+ effectSchemaType(expressionType, expression),
3031
+ flatMap(() => importedSchemaModule(schemaIdentifier.expression)),
2983
3032
  option
2984
3033
  );
2985
3034
  if (isSome2(parsedSchemaModule)) {
@@ -3019,8 +3068,10 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils) {
3019
3068
  const selfTypeNode = schemaTaggedClassTCall.typeArguments[0];
3020
3069
  const schemaIdentifier = schemaTaggedClassTCall.expression;
3021
3070
  if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "TaggedClass") {
3071
+ const expressionType = typeChecker.getTypeAtLocation(expression);
3022
3072
  const parsedSchemaModule = yield* pipe(
3023
- importedSchemaModule(schemaIdentifier.expression),
3073
+ effectSchemaType(expressionType, expression),
3074
+ flatMap(() => importedSchemaModule(schemaIdentifier.expression)),
3024
3075
  option
3025
3076
  );
3026
3077
  if (isSome2(parsedSchemaModule)) {
@@ -3062,8 +3113,10 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils) {
3062
3113
  const selfTypeNode = schemaTaggedErrorTCall.typeArguments[0];
3063
3114
  const schemaIdentifier = schemaTaggedErrorTCall.expression;
3064
3115
  if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "TaggedError") {
3116
+ const expressionType = typeChecker.getTypeAtLocation(expression);
3065
3117
  const parsedSchemaModule = yield* pipe(
3066
- importedSchemaModule(schemaIdentifier.expression),
3118
+ effectSchemaType(expressionType, expression),
3119
+ flatMap(() => importedSchemaModule(schemaIdentifier.expression)),
3067
3120
  option
3068
3121
  );
3069
3122
  if (isSome2(parsedSchemaModule)) {
@@ -3181,8 +3234,10 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils) {
3181
3234
  const selfTypeNode = schemaTaggedRequestTCall.typeArguments[0];
3182
3235
  const schemaIdentifier = schemaTaggedRequestTCall.expression;
3183
3236
  if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "TaggedRequest") {
3237
+ const expressionType = typeChecker.getTypeAtLocation(expression);
3184
3238
  const parsedSchemaModule = yield* pipe(
3185
- importedSchemaModule(schemaIdentifier.expression),
3239
+ effectSchemaType(expressionType, expression),
3240
+ flatMap(() => importedSchemaModule(schemaIdentifier.expression)),
3186
3241
  option
3187
3242
  );
3188
3243
  if (isSome2(parsedSchemaModule)) {
@@ -3801,6 +3856,7 @@ var classSelfMismatch = createDiagnostic({
3801
3856
  const result = yield* pipe(
3802
3857
  typeParser.extendsEffectService(node),
3803
3858
  orElse2(() => typeParser.extendsContextTag(node)),
3859
+ orElse2(() => typeParser.extendsEffectTag(node)),
3804
3860
  orElse2(() => typeParser.extendsSchemaClass(node)),
3805
3861
  orElse2(() => typeParser.extendsSchemaTaggedClass(node)),
3806
3862
  orElse2(() => typeParser.extendsSchemaTaggedError(node)),
@@ -3893,6 +3949,43 @@ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageNam
3893
3949
  })
3894
3950
  });
3895
3951
 
3952
+ // src/diagnostics/effectGenUsesAdapter.ts
3953
+ var effectGenUsesAdapter = createDiagnostic({
3954
+ name: "effectGenUsesAdapter",
3955
+ code: 23,
3956
+ severity: "warning",
3957
+ apply: fn("effectGenUsesAdapter.apply")(function* (sourceFile, report) {
3958
+ const ts = yield* service(TypeScriptApi);
3959
+ const typeParser = yield* service(TypeParser);
3960
+ const nodeToVisit = [];
3961
+ const appendNodeToVisit = (node) => {
3962
+ nodeToVisit.push(node);
3963
+ return void 0;
3964
+ };
3965
+ ts.forEachChild(sourceFile, appendNodeToVisit);
3966
+ while (nodeToVisit.length > 0) {
3967
+ const node = nodeToVisit.shift();
3968
+ ts.forEachChild(node, appendNodeToVisit);
3969
+ if (ts.isCallExpression(node)) {
3970
+ yield* pipe(
3971
+ typeParser.effectGen(node),
3972
+ map3(({ generatorFunction }) => {
3973
+ if (generatorFunction.parameters.length > 0) {
3974
+ const adapter = generatorFunction.parameters[0];
3975
+ report({
3976
+ location: adapter,
3977
+ messageText: `The adapter of Effect.gen is not required anymore, it is now just an alias of pipe.`,
3978
+ fixes: []
3979
+ });
3980
+ }
3981
+ }),
3982
+ ignore
3983
+ );
3984
+ }
3985
+ }
3986
+ })
3987
+ });
3988
+
3896
3989
  // src/diagnostics/effectInVoidSuccess.ts
3897
3990
  var effectInVoidSuccess = createDiagnostic({
3898
3991
  name: "effectInVoidSuccess",
@@ -5410,6 +5503,7 @@ var unsupportedServiceAccessors = createDiagnostic({
5410
5503
  var diagnostics = [
5411
5504
  classSelfMismatch,
5412
5505
  duplicatePackage,
5506
+ effectGenUsesAdapter,
5413
5507
  missingEffectContext,
5414
5508
  missingEffectError,
5415
5509
  missingEffectServiceDependency,
@@ -10996,13 +11090,8 @@ function processNodeMermaid(graph, ctx, ctxL) {
10996
11090
  }
10997
11091
  });
10998
11092
  }
10999
- function generateMarmaidUri(graph, ctxL) {
11093
+ function generateMarmaidUri(code) {
11000
11094
  return gen(function* () {
11001
- const ctx = {
11002
- seenIds: /* @__PURE__ */ new Set()
11003
- };
11004
- const lines = yield* processNodeMermaid(graph, ctx, ctxL);
11005
- const code = "flowchart TB\n" + lines.join("\n");
11006
11095
  const state = JSON.stringify({ code });
11007
11096
  const data = new TextEncoder().encode(state);
11008
11097
  const compressed = deflate_1(data, { level: 9 });
@@ -11010,75 +11099,110 @@ function generateMarmaidUri(graph, ctxL) {
11010
11099
  return "https://www.mermaidchart.com/play#" + pakoString;
11011
11100
  });
11012
11101
  }
11102
+ function getAdjustedNode(sourceFile, position) {
11103
+ return gen(function* () {
11104
+ const ts = yield* service(TypeScriptApi);
11105
+ const tsUtils = yield* service(TypeScriptUtils);
11106
+ const typeChecker = yield* service(TypeCheckerApi);
11107
+ const typeParser = yield* service(TypeParser);
11108
+ const range = tsUtils.toTextRange(position);
11109
+ const maybeNode = pipe(
11110
+ tsUtils.getAncestorNodesInRange(sourceFile, range),
11111
+ filter((_) => ts.isVariableDeclaration(_) || ts.isPropertyDeclaration(_)),
11112
+ filter((_) => tsUtils.isNodeInRange(range)(_.name)),
11113
+ head
11114
+ );
11115
+ if (isNone2(maybeNode)) return void 0;
11116
+ const node = maybeNode.value;
11117
+ const layerNode = node.initializer ? node.initializer : node;
11118
+ const layerType = typeChecker.getTypeAtLocation(layerNode);
11119
+ const maybeLayer = yield* option(typeParser.layerType(layerType, layerNode));
11120
+ if (isNone2(maybeLayer)) return void 0;
11121
+ return { node, layerNode };
11122
+ });
11123
+ }
11124
+ function parseLayerGraph(sourceFile, layerNode) {
11125
+ return gen(function* () {
11126
+ const ts = yield* service(TypeScriptApi);
11127
+ const typeChecker = yield* service(TypeCheckerApi);
11128
+ let lastId = 0;
11129
+ const graphCtx = {
11130
+ services: /* @__PURE__ */ new Map(),
11131
+ serviceTypeToString: /* @__PURE__ */ new Map(),
11132
+ nextId: () => "id" + lastId++
11133
+ };
11134
+ const rootNode = yield* processLayerGraphNode(graphCtx, layerNode, void 0);
11135
+ const ctx = {
11136
+ seenIds: /* @__PURE__ */ new Set()
11137
+ };
11138
+ const mermaidLines = yield* processNodeMermaid(rootNode, ctx, graphCtx);
11139
+ const mermaidCode = "flowchart TB\n" + mermaidLines.join("\n");
11140
+ const textualExplanation = [];
11141
+ const appendInfo = (providesNode, type, kindText) => {
11142
+ const typeString = typeChecker.typeToString(
11143
+ type,
11144
+ void 0,
11145
+ ts.TypeFormatFlags.NoTruncation
11146
+ );
11147
+ const positions = providesNode.map((_) => {
11148
+ const nodePosition = _.node.getStart(sourceFile, false);
11149
+ const { character, line } = ts.getLineAndCharacterOfPosition(sourceFile, nodePosition);
11150
+ const nodeText = _.node.getText().trim().replace(/\n/g, " ").substr(0, 50);
11151
+ return "ln " + (line + 1) + " col " + character + " by `" + nodeText + "`";
11152
+ });
11153
+ textualExplanation.push("- " + typeString + " " + kindText + " at " + positions.join(", "));
11154
+ };
11155
+ for (const providesKey of rootNode.rout) {
11156
+ const providesNode = findInnermostGraphEdge(rootNode, "rout", providesKey);
11157
+ appendInfo(providesNode, graphCtx.services.get(providesKey), "provided");
11158
+ }
11159
+ if (textualExplanation.length > 0) textualExplanation.push("");
11160
+ for (const requiresKey of rootNode.rin) {
11161
+ const requiresNode = findInnermostGraphEdge(rootNode, "rin", requiresKey);
11162
+ appendInfo(requiresNode, graphCtx.services.get(requiresKey), "required");
11163
+ }
11164
+ return { mermaidCode, textualExplanation };
11165
+ });
11166
+ }
11167
+ function effectApiGetLayerGraph(sourceFile, line, character) {
11168
+ return pipe(
11169
+ gen(function* () {
11170
+ const ts = yield* service(TypeScriptApi);
11171
+ const position = ts.getPositionOfLineAndCharacter(sourceFile, line, character);
11172
+ const maybeNodes = yield* getAdjustedNode(sourceFile, position);
11173
+ if (!maybeNodes) return yield* fail(new UnableToProduceLayerGraphError("No node found"));
11174
+ const { layerNode, node } = maybeNodes;
11175
+ const { mermaidCode } = yield* parseLayerGraph(sourceFile, layerNode);
11176
+ return { start: node.pos, end: node.end, mermaidCode };
11177
+ })
11178
+ );
11179
+ }
11013
11180
  function layerInfo(sourceFile, position, quickInfo2) {
11014
11181
  return pipe(
11015
11182
  gen(function* () {
11016
11183
  const ts = yield* service(TypeScriptApi);
11017
- const tsUtils = yield* service(TypeScriptUtils);
11018
- const typeChecker = yield* service(TypeCheckerApi);
11019
- const typeParser = yield* service(TypeParser);
11020
- const range = tsUtils.toTextRange(position);
11021
- const maybeNode = pipe(
11022
- tsUtils.getAncestorNodesInRange(sourceFile, range),
11023
- filter((_) => ts.isVariableDeclaration(_) || ts.isPropertyDeclaration(_)),
11024
- filter((_) => tsUtils.isNodeInRange(range)(_.name)),
11025
- head
11026
- );
11027
- if (isNone2(maybeNode)) return quickInfo2;
11028
- const node = maybeNode.value;
11029
- const layerNode = node.initializer ? node.initializer : node;
11030
- const layerType = typeChecker.getTypeAtLocation(layerNode);
11031
- const maybeLayer = yield* option(typeParser.layerType(layerType, layerNode));
11032
- if (isNone2(maybeLayer)) return quickInfo2;
11033
- let lastId = 0;
11034
- const graphCtx = {
11035
- services: /* @__PURE__ */ new Map(),
11036
- serviceTypeToString: /* @__PURE__ */ new Map(),
11037
- nextId: () => "id" + lastId++
11038
- };
11184
+ const options = yield* service(LanguageServicePluginOptions);
11185
+ const maybeNodes = yield* getAdjustedNode(sourceFile, position);
11186
+ if (!maybeNodes) return quickInfo2;
11187
+ const { layerNode, node } = maybeNodes;
11039
11188
  const layerInfoDisplayParts = yield* pipe(
11040
- processLayerGraphNode(graphCtx, layerNode, void 0),
11189
+ parseLayerGraph(sourceFile, layerNode),
11041
11190
  flatMap(
11042
- (rootNode) => gen(function* () {
11043
- yield* succeed(void 0);
11044
- const lines = [];
11045
- const appendInfo = (providesNode, type, kindText) => {
11046
- const typeString = typeChecker.typeToString(
11047
- type,
11048
- void 0,
11049
- ts.TypeFormatFlags.NoTruncation
11050
- );
11051
- const positions = providesNode.map((_) => {
11052
- const nodePosition = _.node.getStart(sourceFile, false);
11053
- const { character, line } = ts.getLineAndCharacterOfPosition(sourceFile, nodePosition);
11054
- const nodeText = _.node.getText().trim().replace(/\n/g, " ").substr(0, 50);
11055
- return "ln " + (line + 1) + " col " + character + " by `" + nodeText + "`";
11056
- });
11057
- lines.push("- " + typeString + " " + kindText + " at " + positions.join(", "));
11058
- };
11059
- for (const providesKey of rootNode.rout) {
11060
- const providesNode = findInnermostGraphEdge(rootNode, "rout", providesKey);
11061
- appendInfo(providesNode, graphCtx.services.get(providesKey), "provided");
11062
- }
11063
- if (lines.length > 0) lines.push("");
11064
- for (const requiresKey of rootNode.rin) {
11065
- const requiresNode = findInnermostGraphEdge(rootNode, "rin", requiresKey);
11066
- appendInfo(requiresNode, graphCtx.services.get(requiresKey), "required");
11067
- }
11068
- const mermaidUri = yield* option(generateMarmaidUri(rootNode, graphCtx));
11191
+ ({ mermaidCode, textualExplanation }) => gen(function* () {
11069
11192
  const linkParts = [];
11070
- if (isSome2(mermaidUri)) {
11193
+ if (!options.noExternal) {
11194
+ const mermaidUri = yield* generateMarmaidUri(mermaidCode);
11071
11195
  linkParts.push({ kind: "space", text: "\n" });
11072
11196
  linkParts.push({ kind: "link", text: "{@link " });
11073
- linkParts.push({ kind: "linkText", text: mermaidUri.value + " Show full Layer graph" });
11197
+ linkParts.push({ kind: "linkText", text: mermaidUri + " Show full Layer graph" });
11074
11198
  linkParts.push({ kind: "link", text: "}" });
11075
11199
  linkParts.push({ kind: "space", text: "\n" });
11076
11200
  }
11077
- if (lines.length === 0) return linkParts;
11201
+ if (textualExplanation.length === 0) return linkParts;
11078
11202
  return [
11079
11203
  {
11080
11204
  kind: "text",
11081
- text: "```\n/**\n" + lines.map((l) => " * " + l).join("\n") + "\n */\n```\n"
11205
+ text: "```\n/**\n" + textualExplanation.map((l) => " * " + l).join("\n") + "\n */\n```\n"
11082
11206
  },
11083
11207
  ...linkParts
11084
11208
  ];
@@ -13570,6 +13694,45 @@ var init = (modules) => {
13570
13694
  }
13571
13695
  return applicableRenameInfo;
13572
13696
  };
13697
+ info.session?.addProtocolHandler("_effectGetLayerMermaid", (arg) => {
13698
+ const { character, line, path } = arg.arguments;
13699
+ const normalizedPath = modules.typescript.server.toNormalizedPath(path);
13700
+ const projectService = info.project.projectService;
13701
+ const scriptInfo = projectService.getScriptInfoForNormalizedPath(normalizedPath);
13702
+ if (scriptInfo) {
13703
+ const targetProject = scriptInfo.getDefaultProject();
13704
+ if (targetProject) {
13705
+ const program = targetProject.getLanguageService().getProgram();
13706
+ if (program) {
13707
+ const sourceFile = targetProject.getSourceFile(scriptInfo.path);
13708
+ if (sourceFile) {
13709
+ return pipe(
13710
+ effectApiGetLayerGraph(sourceFile, line, character),
13711
+ map3((response) => ({
13712
+ response: {
13713
+ success: true,
13714
+ ...response
13715
+ }
13716
+ })),
13717
+ runNano(program),
13718
+ getOrElse((e) => ({
13719
+ response: {
13720
+ success: false,
13721
+ error: e.message
13722
+ }
13723
+ }))
13724
+ );
13725
+ }
13726
+ }
13727
+ }
13728
+ }
13729
+ return {
13730
+ response: {
13731
+ success: false,
13732
+ error: "No source file found"
13733
+ }
13734
+ };
13735
+ });
13573
13736
  return proxy;
13574
13737
  }
13575
13738
  return { create, onConfigurationChanged };