How about something like this? I just wrote this so it's not "carefully" tested, but seems to work.
DROP FUNCTION IF EXISTS PrettyJSONInternal
GO
CREATE OR ALTER FUNCTION PrettyJSONInternal (
@JSON NVARCHAR(MAX),
@IndentString AS NVARCHAR(32) = ' ',
@Level INT = 0,
@NL NVARCHAR(2),
@CurrIndent AS NVARCHAR(MAX) = ' '
) RETURNS NVARCHAR(MAX)
AS BEGIN
DECLARE @JSONTbl AS TABLE (i INT IDENTITY(0,1), k NVARCHAR(MAX), v NVARCHAR(MAX), t INT)
DECLARE @N AS INT, @I AS INT = 0
INSERT INTO @JSONTbl (k, v, t)
SELECT [key], [value], [type]
FROM OPENJSON(@JSON)
SET @N = @@ROWCOUNT
DECLARE @Return AS NVARCHAR(MAX) = ''
IF @Level = 0 SET @Return = '{' + @NL
SET @I = 0
WHILE @I < @N
BEGIN
DECLARE @EOL AS NVARCHAR(10) = ',' + @NL
IF @I + 1 = @N SET @EOL = @NL
DECLARE @k AS NVARCHAR(MAX), @v AS NVARCHAR(MAX), @t AS INT
SELECT @k = k, @v = v, @t = t FROM @JSONTbl WHERE i = @I
IF @t = 1
SET @Return = @Return + @CurrIndent + '"' + @k + '" : "' + @v + '"' + @EOL
ELSE IF @t = 2 OR @t = 3
SET @Return = @Return + @CurrIndent + '"' + @k + '" : ' + @v + @EOL
ELSE IF @t = 4
SET @Return = @Return + @CurrIndent + '"' + @k + '" : [' + @NL +
dbo.PrettyJSONInternal(@v, @IndentString, @Level + 1, @NL, @CurrIndent + @IndentString) +
@CurrIndent + ']' + @EOL
ELSE IF @t = 5
SET @Return = @Return + @CurrIndent + '{' + @NL +
dbo.PrettyJSONInternal(@v, @IndentString, @Level + 1, @NL, @CurrIndent + @IndentString) +
@CurrIndent + '}' + @EOL
SET @I = @I + 1
END
IF @Level = 0 SET @Return = @Return + '}' + @NL
RETURN @Return
END
GO
CREATE OR ALTER FUNCTION PrettyJSON (
@JSON NVARCHAR(MAX)
) RETURNS NVARCHAR(MAX)
AS BEGIN
RETURN dbo.PrettyJSONInternal(@JSON, ' ', 0, CHAR(13) + CHAR(10), ' ')
END
GO