@effect/language-service 0.37.0 → 0.38.1

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
@@ -2622,8 +2622,7 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils) {
2622
2622
  node,
2623
2623
  effectModule,
2624
2624
  generatorFunction,
2625
- body: generatorFunction.body,
2626
- functionStar: generatorFunction.getFirstToken()
2625
+ body: generatorFunction.body
2627
2626
  }))
2628
2627
  );
2629
2628
  },
@@ -2670,8 +2669,7 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils) {
2670
2669
  node,
2671
2670
  effectModule,
2672
2671
  generatorFunction,
2673
- body: generatorFunction.body,
2674
- functionStar: generatorFunction.getFirstToken()
2672
+ body: generatorFunction.body
2675
2673
  }))
2676
2674
  );
2677
2675
  },
@@ -2723,8 +2721,7 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils) {
2723
2721
  node,
2724
2722
  generatorFunction,
2725
2723
  effectModule,
2726
- body: generatorFunction.body,
2727
- functionStar: generatorFunction.getFirstToken()
2724
+ body: generatorFunction.body
2728
2725
  }))
2729
2726
  );
2730
2727
  },
@@ -4564,6 +4561,7 @@ var missingStarInYieldEffectGen = createDiagnostic({
4564
4561
  apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile, report) {
4565
4562
  const ts = yield* service(TypeScriptApi);
4566
4563
  const typeParser = yield* service(TypeParser);
4564
+ const tsUtils = yield* service(TypeScriptUtils);
4567
4565
  const brokenGenerators = /* @__PURE__ */ new Set();
4568
4566
  const brokenYields = /* @__PURE__ */ new Set();
4569
4567
  const nodeToVisit = [];
@@ -4586,9 +4584,9 @@ var missingStarInYieldEffectGen = createDiagnostic({
4586
4584
  typeParser.effectGen(effectGenNode),
4587
4585
  orElse2(() => typeParser.effectFnUntracedGen(effectGenNode)),
4588
4586
  orElse2(() => typeParser.effectFnGen(effectGenNode)),
4589
- map3(({ functionStar }) => {
4590
- if (functionStar) {
4591
- brokenGenerators.add(functionStar);
4587
+ map3(({ generatorFunction }) => {
4588
+ if (generatorFunction) {
4589
+ brokenGenerators.add(ts.getTokenPosOfNode(generatorFunction, tsUtils.getSourceFileOfNode(node)));
4592
4590
  }
4593
4591
  brokenYields.add(node);
4594
4592
  }),
@@ -4598,8 +4596,8 @@ var missingStarInYieldEffectGen = createDiagnostic({
4598
4596
  }
4599
4597
  }
4600
4598
  brokenGenerators.forEach(
4601
- (node) => report({
4602
- location: node,
4599
+ (pos) => report({
4600
+ location: { pos, end: pos + "function".length },
4603
4601
  messageText: `Seems like you used yield instead of yield* inside this Effect.gen.`,
4604
4602
  fixes: []
4605
4603
  })
@@ -11520,6 +11518,301 @@ var functionToArrow = createRefactor({
11520
11518
  })
11521
11519
  });
11522
11520
 
11521
+ // src/refactors/layerMagic.ts
11522
+ function sortDependencies(nodes) {
11523
+ const result = [];
11524
+ const visited = /* @__PURE__ */ new Set();
11525
+ const visiting = /* @__PURE__ */ new Set();
11526
+ const cycles = [];
11527
+ const providesMap = /* @__PURE__ */ new Map();
11528
+ Object.entries(nodes).forEach(([nodeId, node]) => {
11529
+ node.provides.forEach((service2) => {
11530
+ if (!providesMap.has(service2)) {
11531
+ providesMap.set(service2, []);
11532
+ }
11533
+ providesMap.get(service2).push(nodeId);
11534
+ });
11535
+ });
11536
+ providesMap.forEach((nodeIds) => {
11537
+ nodeIds.sort((a, b) => {
11538
+ const nodeA = nodes[a];
11539
+ const nodeB = nodes[b];
11540
+ return nodeA.requires.length - nodeB.requires.length;
11541
+ });
11542
+ });
11543
+ const visit = (nodeId, path) => {
11544
+ if (visited.has(nodeId)) {
11545
+ return;
11546
+ }
11547
+ if (visiting.has(nodeId)) {
11548
+ const cycleStart = path.indexOf(nodeId);
11549
+ const cycle = path.slice(cycleStart).concat([nodeId]);
11550
+ const cycleServices = cycle.map((id) => {
11551
+ const node2 = nodes[id];
11552
+ return `${node2.provides.join(", ")} (requires: ${node2.requires.join(", ")})`;
11553
+ });
11554
+ cycles.push(cycleServices);
11555
+ return;
11556
+ }
11557
+ visiting.add(nodeId);
11558
+ const currentPath = [...path, nodeId];
11559
+ const dependencies = /* @__PURE__ */ new Set();
11560
+ const node = nodes[nodeId];
11561
+ node.requires.forEach((requiredService) => {
11562
+ const providers = providesMap.get(requiredService) || [];
11563
+ providers.forEach((providerId) => {
11564
+ if (providerId !== nodeId) {
11565
+ dependencies.add(providerId);
11566
+ }
11567
+ });
11568
+ });
11569
+ dependencies.forEach((depId) => {
11570
+ visit(depId, currentPath);
11571
+ });
11572
+ visiting.delete(nodeId);
11573
+ visited.add(nodeId);
11574
+ result.push(node);
11575
+ };
11576
+ Object.keys(nodes).forEach((nodeId) => {
11577
+ if (!visited.has(nodeId)) {
11578
+ visit(nodeId, []);
11579
+ }
11580
+ });
11581
+ return {
11582
+ sorted: result,
11583
+ cycles,
11584
+ hasCycles: cycles.length > 0
11585
+ };
11586
+ }
11587
+ var layerMagic = createRefactor({
11588
+ name: "layerMagic",
11589
+ description: "Layer Magic",
11590
+ apply: fn("layerMagic.apply")(function* (sourceFile, textRange) {
11591
+ const ts = yield* service(TypeScriptApi);
11592
+ const tsUtils = yield* service(TypeScriptUtils);
11593
+ const typeChecker = yield* service(TypeCheckerApi);
11594
+ const typeParser = yield* service(TypeParser);
11595
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
11596
+ const layerIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
11597
+ sourceFile,
11598
+ "effect",
11599
+ "Layer"
11600
+ ) || "Layer";
11601
+ const extractArrayLiteral = (node) => {
11602
+ if (ts.isArrayLiteralExpression(node)) {
11603
+ return pipe(
11604
+ all(...node.elements.map((element) => extractLayers(element, false))),
11605
+ map3(flatten)
11606
+ );
11607
+ }
11608
+ return TypeParserIssue.issue;
11609
+ };
11610
+ const extractLayerExpression = (node) => {
11611
+ if (ts.isExpression(node)) {
11612
+ return pipe(
11613
+ typeParser.layerType(typeChecker.getTypeAtLocation(node), node),
11614
+ map3((_) => [{ node, ..._ }])
11615
+ );
11616
+ }
11617
+ return TypeParserIssue.issue;
11618
+ };
11619
+ const extractLayerApi = (node) => {
11620
+ if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression) && ts.idText(node.expression.expression) === layerIdentifier && ts.isIdentifier(node.expression.name) && ["provide", "provideMerge", "merge", "mergeAll"].map((_) => _.toLowerCase()).indexOf(
11621
+ ts.idText(node.expression.name).toLowerCase()
11622
+ ) > -1) {
11623
+ return pipe(
11624
+ all(...node.arguments.map((element) => extractLayers(element, false))),
11625
+ map3(flatten)
11626
+ );
11627
+ }
11628
+ return TypeParserIssue.issue;
11629
+ };
11630
+ const extractPipeSequencing = (node) => {
11631
+ return pipe(
11632
+ typeParser.pipeCall(node),
11633
+ flatMap((_) => {
11634
+ return all(...[_.subject, ..._.args].map((element) => extractLayers(element, true)));
11635
+ }),
11636
+ map3(flatten)
11637
+ );
11638
+ };
11639
+ const extractLayers = cachedBy(
11640
+ fn("layerMagic.apply.extractLayerArray")(function* (node, _inPipeContext) {
11641
+ return yield* pipe(
11642
+ extractArrayLiteral(node),
11643
+ orElse2(() => extractLayerApi(node)),
11644
+ _inPipeContext ? (x) => x : orElse2(() => extractPipeSequencing(node)),
11645
+ orElse2(() => extractLayerExpression(node))
11646
+ );
11647
+ }),
11648
+ "layerMagic.apply.extractLayerArray",
11649
+ (node) => node
11650
+ );
11651
+ const adjustedNode = (node) => {
11652
+ if (ts.isIdentifier(node) && ts.isVariableDeclaration(node.parent) && node.parent.initializer) {
11653
+ return adjustedNode(node.parent.initializer);
11654
+ }
11655
+ if (ts.isIdentifier(node) && ts.isPropertyDeclaration(node.parent) && node.parent.initializer) {
11656
+ return adjustedNode(node.parent.initializer);
11657
+ }
11658
+ return node;
11659
+ };
11660
+ const computeAsAnyAsLayerRefactor = (node) => {
11661
+ const atLocation = adjustedNode(node);
11662
+ return pipe(
11663
+ extractLayers(atLocation, false),
11664
+ flatMap(
11665
+ (extractedLayer) => extractedLayer.length < 1 ? TypeParserIssue.issue : succeed(extractedLayer)
11666
+ ),
11667
+ map3((extractedLayers) => ({
11668
+ kind: "refactor.rewrite.effect.layerMagicPrepare",
11669
+ description: "Prepare layers for automatic composition",
11670
+ apply: pipe(
11671
+ gen(function* () {
11672
+ const changeTracker = yield* service(ChangeTracker);
11673
+ const memory = /* @__PURE__ */ new Map();
11674
+ for (const layer of extractedLayers) {
11675
+ yield* typeCheckerUtils.appendToUniqueTypesMap(
11676
+ memory,
11677
+ layer.ROut,
11678
+ (_) => succeed((_.flags & ts.TypeFlags.Never) !== 0)
11679
+ );
11680
+ }
11681
+ const typeReferences = pipe(
11682
+ fromIterable(memory.values()),
11683
+ sort(typeCheckerUtils.deterministicTypeOrder),
11684
+ map5((_) => typeChecker.typeToTypeNode(_, void 0, ts.NodeBuilderFlags.NoTruncation)),
11685
+ filter((_) => !!_)
11686
+ );
11687
+ const newDeclaration = ts.factory.createAsExpression(
11688
+ ts.factory.createAsExpression(
11689
+ ts.factory.createArrayLiteralExpression(extractedLayers.map((_) => _.node)),
11690
+ ts.factory.createTypeReferenceNode("any")
11691
+ ),
11692
+ ts.factory.createTypeReferenceNode(
11693
+ ts.factory.createQualifiedName(ts.factory.createIdentifier(layerIdentifier), "Layer"),
11694
+ typeReferences.length === 0 ? [
11695
+ ts.factory.createTypeReferenceNode("never")
11696
+ ] : [ts.factory.createUnionTypeNode(typeReferences)]
11697
+ )
11698
+ );
11699
+ changeTracker.replaceNode(sourceFile, atLocation, newDeclaration, {
11700
+ leadingTriviaOption: ts.textChanges.LeadingTriviaOption.IncludeAll,
11701
+ trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude
11702
+ });
11703
+ }),
11704
+ provideService(TypeScriptApi, ts)
11705
+ )
11706
+ }))
11707
+ );
11708
+ };
11709
+ const parseAsAnyAsLayer = (node) => {
11710
+ if (ts.isAsExpression(node) && ts.isTypeReferenceNode(node.type)) {
11711
+ const expression = node.expression;
11712
+ if (ts.isAsExpression(expression) && expression.type.kind === ts.SyntaxKind.AnyKeyword) {
11713
+ return pipe(
11714
+ typeParser.layerType(typeChecker.getTypeAtLocation(node.type), node.type),
11715
+ map3((_) => ({ node, ..._, castedStructure: expression.expression }))
11716
+ );
11717
+ }
11718
+ }
11719
+ return TypeParserIssue.issue;
11720
+ };
11721
+ const computeBuildRefactor = (node) => {
11722
+ const atLocation = adjustedNode(node);
11723
+ return pipe(
11724
+ parseAsAnyAsLayer(atLocation),
11725
+ flatMap(
11726
+ (_targetLayer) => pipe(
11727
+ extractArrayLiteral(_targetLayer.castedStructure),
11728
+ orElse2(() => extractLayers(_targetLayer.castedStructure, false)),
11729
+ flatMap(
11730
+ (extractedLayer) => extractedLayer.length < 1 ? TypeParserIssue.issue : succeed(extractedLayer)
11731
+ ),
11732
+ map3((extractedLayers) => ({
11733
+ kind: "refactor.rewrite.effect.layerMagicBuild",
11734
+ description: "Compose layers automatically with target output services",
11735
+ apply: gen(function* () {
11736
+ const changeTracker = yield* service(ChangeTracker);
11737
+ const memory = /* @__PURE__ */ new Map();
11738
+ const { allIndexes: outputIndexes } = yield* typeCheckerUtils.appendToUniqueTypesMap(
11739
+ memory,
11740
+ _targetLayer.ROut,
11741
+ (_) => succeed((_.flags & ts.TypeFlags.Never) !== 0)
11742
+ );
11743
+ const nodes = {};
11744
+ for (let i = 0; i < extractedLayers.length; i++) {
11745
+ const layer = extractedLayers[i];
11746
+ const { allIndexes: providedIndexes } = yield* typeCheckerUtils.appendToUniqueTypesMap(
11747
+ memory,
11748
+ layer.ROut,
11749
+ (_) => succeed((_.flags & ts.TypeFlags.Never) !== 0)
11750
+ );
11751
+ const { allIndexes: requiredIndexes } = yield* typeCheckerUtils.appendToUniqueTypesMap(
11752
+ memory,
11753
+ layer.RIn,
11754
+ (_) => succeed((_.flags & ts.TypeFlags.Never) !== 0)
11755
+ );
11756
+ nodes[`node_${i}`] = {
11757
+ provides: providedIndexes.filter((_) => requiredIndexes.indexOf(_) === -1),
11758
+ // only provide indexes that are not required
11759
+ requires: requiredIndexes,
11760
+ node: layer.node
11761
+ };
11762
+ }
11763
+ const sortResult = sortDependencies(nodes);
11764
+ const sortedNodes = sortResult.sorted.reverse();
11765
+ const missingOutput = new Set(outputIndexes);
11766
+ const missingInternal = /* @__PURE__ */ new Set();
11767
+ const outputEntry = [];
11768
+ for (const graphNode of sortedNodes) {
11769
+ const mergeOutput = graphNode.provides.filter((_) => missingOutput.has(_));
11770
+ const provideInternal = graphNode.provides.filter((_) => missingInternal.has(_));
11771
+ graphNode.requires.forEach((_) => missingInternal.add(_));
11772
+ mergeOutput.forEach((_) => missingOutput.delete(_));
11773
+ outputEntry.push({
11774
+ merges: mergeOutput.length > 0,
11775
+ provides: provideInternal.length > 0,
11776
+ node: graphNode.node
11777
+ });
11778
+ }
11779
+ const newDeclaration = ts.factory.createCallExpression(
11780
+ ts.factory.createPropertyAccessExpression(
11781
+ outputEntry[0].node,
11782
+ "pipe"
11783
+ ),
11784
+ [],
11785
+ outputEntry.slice(1).map(
11786
+ (_) => ts.factory.createCallExpression(
11787
+ ts.factory.createPropertyAccessExpression(
11788
+ ts.factory.createIdentifier(layerIdentifier),
11789
+ _.merges && _.provides ? "provideMerge" : _.merges ? "merge" : "provide"
11790
+ ),
11791
+ [],
11792
+ [_.node]
11793
+ )
11794
+ )
11795
+ );
11796
+ changeTracker.replaceNode(sourceFile, atLocation, newDeclaration, {
11797
+ leadingTriviaOption: ts.textChanges.LeadingTriviaOption.IncludeAll,
11798
+ trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude
11799
+ });
11800
+ })
11801
+ }))
11802
+ )
11803
+ )
11804
+ );
11805
+ };
11806
+ const parentNodes = tsUtils.getAncestorNodesInRange(sourceFile, textRange);
11807
+ if (parentNodes.length === 0) return yield* fail(new RefactorNotApplicableError());
11808
+ return yield* pipe(
11809
+ firstSuccessOf(parentNodes.map(computeBuildRefactor)),
11810
+ orElse2(() => firstSuccessOf(parentNodes.map(computeAsAnyAsLayerRefactor))),
11811
+ orElse2(() => fail(new RefactorNotApplicableError()))
11812
+ );
11813
+ })
11814
+ });
11815
+
11523
11816
  // src/refactors/makeSchemaOpaque.ts
11524
11817
  var _findSchemaVariableDeclaration = fn(
11525
11818
  "makeSchemaOpaque._findSchemaVariableDeclaration"
@@ -12732,6 +13025,7 @@ var wrapWithPipe = createRefactor({
12732
13025
 
12733
13026
  // src/refactors.ts
12734
13027
  var refactors = [
13028
+ layerMagic,
12735
13029
  asyncAwaitToGen,
12736
13030
  asyncAwaitToGenTryPromise,
12737
13031
  asyncAwaitToFn,