-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Graph-based heuristics for arranging the
-- order of sections in the schema docs
module Swarm.Doc.Schema.Arrangement (sortAndPruneSchemas) where

import Data.Graph
import Data.Set qualified as Set
import Swarm.Doc.Schema.Parse
import Swarm.Doc.Schema.Refined
import Swarm.Doc.Schema.SchemaType

-- | Sort the schemas in topological order.
--
-- Only includes schema files that are reachable from
-- the root schema
-- (i.e. exclude @entities.json@ and @recipes.json@,
-- which are used independently to validate @entities.yaml@
-- and @recipes.yaml@).
sortAndPruneSchemas ::
  SchemaIdReference ->
  [SchemaData] ->
  [SchemaData]
sortAndPruneSchemas :: SchemaIdReference -> [SchemaData] -> [SchemaData]
sortAndPruneSchemas SchemaIdReference
rootSchemaKey [SchemaData]
schemas =
  forall a. [a] -> [a]
reverse forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [SCC a] -> [a]
flattenSCCs forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall key node. Ord key => [(node, key, [key])] -> [SCC node]
stronglyConnComp forall a b. (a -> b) -> a -> b
$ [(SchemaData, SchemaIdReference, [SchemaIdReference])]
reachableEdges
 where
  rawEdgeList :: [(SchemaData, SchemaIdReference, [SchemaIdReference])]
rawEdgeList = forall a b. (a -> b) -> [a] -> [b]
map SchemaData -> (SchemaData, SchemaIdReference, [SchemaIdReference])
getNodeEdgesEntry [SchemaData]
schemas
  (Graph
graph, Vertex -> (SchemaData, SchemaIdReference, [SchemaIdReference])
_nodeFromVertex, SchemaIdReference -> Maybe Vertex
vertexFromKey) = forall key node.
Ord key =>
[(node, key, [key])]
-> (Graph, Vertex -> (node, key, [key]), key -> Maybe Vertex)
graphFromEdges [(SchemaData, SchemaIdReference, [SchemaIdReference])]
rawEdgeList
  reachableVertices :: Set Vertex
reachableVertices = forall a. Ord a => [a] -> Set a
Set.fromList forall a b. (a -> b) -> a -> b
$ forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] (Graph -> Vertex -> [Vertex]
reachable Graph
graph) forall a b. (a -> b) -> a -> b
$ SchemaIdReference -> Maybe Vertex
vertexFromKey SchemaIdReference
rootSchemaKey

  reachableEdges :: [(SchemaData, SchemaIdReference, [SchemaIdReference])]
reachableEdges = forall a. (a -> Bool) -> [a] -> [a]
filter forall {a} {c}. (a, SchemaIdReference, c) -> Bool
f [(SchemaData, SchemaIdReference, [SchemaIdReference])]
rawEdgeList
  f :: (a, SchemaIdReference, c) -> Bool
f (a
_, SchemaIdReference
k, c
_) = forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (forall a. Ord a => a -> Set a -> Bool
`Set.member` Set Vertex
reachableVertices) forall b c a. (b -> c) -> (a -> b) -> a -> c
. SchemaIdReference -> Maybe Vertex
vertexFromKey forall a b. (a -> b) -> a -> b
$ SchemaIdReference
k

getNodeEdgesEntry ::
  SchemaData ->
  (SchemaData, SchemaIdReference, [SchemaIdReference])
getNodeEdgesEntry :: SchemaData -> (SchemaData, SchemaIdReference, [SchemaIdReference])
getNodeEdgesEntry sd :: SchemaData
sd@(SchemaData FilePath
fp ToplevelSchema
schem [Pandoc]
_) =
  ( SchemaData
sd
  , FilePath -> SchemaIdReference
fromFilePath FilePath
fp
  , forall a. Set a -> [a]
Set.toList forall a b. (a -> b) -> a -> b
$ SwarmSchema -> Set SchemaIdReference
extractReferences forall a b. (a -> b) -> a -> b
$ ToplevelSchema -> SwarmSchema
content ToplevelSchema
schem
  )