mirror of
https://github.com/apple/pkl.git
synced 2026-04-10 10:53:40 +02:00
Improve Formatter API (#1505)
- pass `GrammarVersion` to constructor instead of passing it to each `format` method - replace `format(Path): String` with `format(Reader, Appendable)` - instead of picking which overloads besides `format(String): String` might be useful, offer a single generalized method that streams input and output - add `@Throws(IOException::class)` to ensure that Java callers can catch this exception - deprecate old methods
This commit is contained in:
@@ -47,7 +47,7 @@ constructor(
|
||||
private val errWriter: Writer = System.err.writer(),
|
||||
) : CliCommand(CliBaseOptions()) {
|
||||
private fun format(contents: String): String {
|
||||
return Formatter().format(contents, grammarVersion)
|
||||
return Formatter(grammarVersion).format(contents)
|
||||
}
|
||||
|
||||
private fun writeErrLine(error: String) {
|
||||
|
||||
@@ -15,14 +15,24 @@
|
||||
*/
|
||||
package org.pkl.formatter
|
||||
|
||||
import java.io.IOException
|
||||
import java.io.Reader
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import kotlin.jvm.Throws
|
||||
import org.pkl.formatter.ast.ForceLine
|
||||
import org.pkl.formatter.ast.Nodes
|
||||
import org.pkl.parser.GenericParser
|
||||
|
||||
/** A formatter for Pkl files that applies canonical formatting rules. */
|
||||
class Formatter {
|
||||
/**
|
||||
* A formatter for Pkl files that applies canonical formatting rules.
|
||||
*
|
||||
* @param grammarVersion grammar compatibility version
|
||||
*/
|
||||
class Formatter
|
||||
@JvmOverloads
|
||||
constructor(private val grammarVersion: GrammarVersion = GrammarVersion.latest()) {
|
||||
|
||||
/**
|
||||
* Formats a Pkl file from the given file path.
|
||||
*
|
||||
@@ -32,8 +42,9 @@ class Formatter {
|
||||
* @throws java.io.IOException if the file cannot be read
|
||||
*/
|
||||
@JvmOverloads
|
||||
@Deprecated(message = "use format(path.readText()) instead")
|
||||
fun format(path: Path, grammarVersion: GrammarVersion = GrammarVersion.latest()): String {
|
||||
return format(Files.readString(path), grammarVersion)
|
||||
return Formatter(grammarVersion).format(Files.readString(path))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,16 +54,41 @@ class Formatter {
|
||||
* @param grammarVersion grammar compatibility version
|
||||
* @return the formatted Pkl source code as a string
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun format(text: String, grammarVersion: GrammarVersion = GrammarVersion.latest()): String {
|
||||
val parser = GenericParser()
|
||||
val builder = Builder(text, grammarVersion)
|
||||
val gen = Generator()
|
||||
val ast = parser.parseModule(text)
|
||||
val formatAst = builder.format(ast)
|
||||
@Deprecated(message = "use Formatter(grammarVersion).format(text) instead")
|
||||
fun format(text: String, grammarVersion: GrammarVersion): String {
|
||||
return Formatter(grammarVersion).format(text)
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given Pkl source code text.
|
||||
*
|
||||
* @param text the Pkl source code to format
|
||||
* @return the formatted Pkl source code as a string
|
||||
*/
|
||||
fun format(text: String): String {
|
||||
return buildString { format(text, this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given Pkl source code text.
|
||||
*
|
||||
* It is the caller's responsibility to close [input], and, if applicable, [output].
|
||||
*
|
||||
* @param input the Pkl source code to format
|
||||
* @param output the formatted Pkl source code
|
||||
* @throws java.io.IOException if an I/O error occurs during reading or writing
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun format(input: Reader, output: Appendable) {
|
||||
format(input.readText(), output)
|
||||
}
|
||||
|
||||
private fun format(input: String, output: Appendable) {
|
||||
val ast = GenericParser().parseModule(input)
|
||||
val formatAst = Builder(input, grammarVersion).format(ast)
|
||||
// force a line at the end of the file
|
||||
gen.generate(Nodes(listOf(formatAst, ForceLine)))
|
||||
return gen.toString()
|
||||
val nodes = Nodes(listOf(formatAst, ForceLine))
|
||||
Generator(output).generate(nodes)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* Copyright © 2025-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,8 +29,7 @@ import org.pkl.formatter.ast.SpaceOrLine
|
||||
import org.pkl.formatter.ast.Text
|
||||
import org.pkl.formatter.ast.Wrap
|
||||
|
||||
internal class Generator {
|
||||
private val buf: StringBuilder = StringBuilder()
|
||||
internal class Generator(private val buf: Appendable) {
|
||||
private var indent: Int = 0
|
||||
private var size: Int = 0
|
||||
private val wrapped: MutableSet<Int> = mutableSetOf()
|
||||
@@ -138,10 +137,6 @@ internal class Generator {
|
||||
return if (beforeLast is Text) beforeLast.text.length else 0
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return buf.toString()
|
||||
}
|
||||
|
||||
companion object {
|
||||
// max line length
|
||||
const val MAX = 100
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* Copyright © 2025-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@ package org.pkl.formatter
|
||||
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.isRegularFile
|
||||
import kotlin.io.path.readText
|
||||
import kotlin.reflect.KClass
|
||||
import org.pkl.commons.test.InputOutputTestEngine
|
||||
import org.pkl.parser.ParserError
|
||||
@@ -58,16 +59,10 @@ abstract class AbstractFormatterSnippetTestsEngine : InputOutputTestEngine() {
|
||||
class FormatterSnippetTestsEngine : AbstractFormatterSnippetTestsEngine() {
|
||||
override val testClass: KClass<*> = FormatterSnippetTests::class
|
||||
|
||||
override fun generateOutputFor(inputFile: Path): Pair<Boolean, String> {
|
||||
val formatter = Formatter()
|
||||
val (success, output) =
|
||||
try {
|
||||
val res = formatter.format(inputFile)
|
||||
true to res
|
||||
} catch (_: ParserError) {
|
||||
false to ""
|
||||
}
|
||||
|
||||
return success to output
|
||||
}
|
||||
override fun generateOutputFor(inputFile: Path): Pair<Boolean, String> =
|
||||
try {
|
||||
true to Formatter().format(inputFile.readText())
|
||||
} catch (_: ParserError) {
|
||||
false to ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* Copyright © 2025-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -120,4 +120,12 @@ class FormatterTest {
|
||||
assertThat(format(src)).isEqualTo("\n")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `read from Reader and write to Appendable`() {
|
||||
val input = " x = 42".reader()
|
||||
val output = StringBuilder()
|
||||
Formatter().format(input, output)
|
||||
assertThat(output.toString()).isEqualTo("x = 42\n")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user