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