Compare commits

..

1 Commits

Author SHA1 Message Date
Islon Scherer d5b6038147 Prepare 0.29.0 release 2025-07-24 19:05:24 +02:00
172 changed files with 702 additions and 7212 deletions
-1
View File
@@ -63,7 +63,6 @@
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="false" module="true" />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
-1
View File
@@ -8,5 +8,4 @@ See link:CONTRIBUTING.adoc[] for general contribution guidelines.
* https://github.com/bioball[Daniel Chao]
* https://github.com/stackoverflow[Islon Scherer]
* https://github.com/HT154[Jen Basch]
* https://github.com/holzensp[Philip Hölzenspies]
+8 -8
View File
@@ -5,7 +5,7 @@ net.bytebuddy:byte-buddy:1.15.11=jmh,jmhRuntimeClasspath,testCompileClasspath,te
net.sf.jopt-simple:jopt-simple:5.0.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.apache.commons:commons-math3:3.6.1=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=jmhCompileClasspath,jmhImplementationDependenciesMetadata,testCompileClasspath,testImplementationDependenciesMetadata
org.assertj:assertj-core:3.27.4=jmh,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.assertj:assertj-core:3.27.3=jmh,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.compiler:compiler:24.1.2=graal
org.graalvm.polyglot:polyglot:24.1.2=jmh,jmhRuntimeClasspath,truffle
org.graalvm.sdk:collections:24.1.2=graal,jmh,jmhRuntimeClasspath,truffle
@@ -35,13 +35,13 @@ org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21=jmh,jmhCompileClasspath,jmhImplem
org.jetbrains.kotlin:kotlin-stdlib:2.0.21=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains:annotations:13.0=jmh,jmhCompileClasspath,jmhRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.4=testRuntimeClasspath
org.junit:junit-bom:5.13.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.3=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.3=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.3=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.3=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.3=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.3=testRuntimeClasspath
org.junit:junit-bom:5.13.3=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.msgpack:msgpack-core:0.9.8=jmh,jmhRuntimeClasspath
org.openjdk.jmh:jmh-core:1.37=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.openjdk.jmh:jmh-generator-asm:1.37=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
+2 -2
View File
@@ -1,6 +1,6 @@
name: main
title: Main Project
version: 0.30.0-dev
prerelease: true
version: 0.29.0
prerelease: false
nav:
- nav.adoc
+8 -8
View File
@@ -4,7 +4,7 @@
io.leangen.geantyref:geantyref:1.3.16=testRuntimeClasspath
net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata
org.assertj:assertj-core:3.27.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.polyglot:polyglot:24.1.2=testRuntimeClasspath
org.graalvm.sdk:collections:24.1.2=testRuntimeClasspath
org.graalvm.sdk:graal-sdk:24.1.2=testRuntimeClasspath
@@ -32,13 +32,13 @@ org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21=testCompileClasspath,testImplemen
org.jetbrains.kotlin:kotlin-stdlib:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains:annotations:13.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.4=testRuntimeClasspath
org.junit:junit-bom:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.3=testRuntimeClasspath
org.junit:junit-bom:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.msgpack:msgpack-core:0.9.8=testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.organicdesign:Paguro:3.10.3=testRuntimeClasspath
@@ -3,10 +3,10 @@
// the following attributes must be updated immediately before a release
// pkl version corresponding to current git commit without -dev suffix or git hash
:pkl-version-no-suffix: 0.30.0
:pkl-version-no-suffix: 0.29.0
// tells whether pkl version corresponding to current git commit
// is a release version (:is-release-version: '') or dev version (:!is-release-version:)
:!is-release-version:
:is-release-version: ''
// the remaining attributes do not need to be updated regularly
@@ -23,9 +23,9 @@ endif::[]
:uri-maven-docsite: https://central.sonatype.com
:uri-snapshot-repo: https://central.sonatype.com/repository/maven-snapshots
:uri-sonatype: https://s01.oss.sonatype.org/content/groups/public
:uri-maven-repo: https://central.sonatype.com/repository/maven-snapshots
:uri-maven-repo: https://s01.oss.sonatype.org/content/groups/public
ifdef::is-release-version[]
:uri-maven-repo: https://repo1.maven.org/maven2
endif::[]
@@ -150,5 +150,4 @@ endif::[]
:uri-pkl-roadmap: https://github.com/orgs/apple/projects/12/views/1
// TODO: figure out what the correct URL should be
:uri-sonatype-snapshot-download: https://s01.oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=org.pkl-lang&v={pkl-artifact-version}
+2 -2
View File
@@ -5,7 +5,7 @@ include::ROOT:partial$component-attributes.adoc[]
:uri-pkl-codegen-java-download: {uri-sonatype-snapshot-download}&a=pkl-cli-codegen-java&e=jar
ifdef::is-release-version[]
:uri-pkl-codegen-java-download: {github-releases}/pkl-codegen-java
:uri-pkl-cli-codegen-java-download: {github-releases}/pkl-codegen-java
endif::[]
The Java source code generator takes Pkl class definitions as an input, and generates corresponding Java classes with equally named properties.
@@ -33,7 +33,7 @@ The `pkl-codegen-java` library is available {uri-pkl-codegen-java-maven-module}[
It requires Java 17 or higher.
ifndef::is-release-version[]
NOTE: Snapshots are published to repository `{uri-snapshot-repo}`.
NOTE: Snapshots are published to repository `{uri-sonatype}`.
endif::[]
==== Gradle
-53
View File
@@ -2,7 +2,6 @@
include::ROOT:partial$component-attributes.adoc[]
:uri-homebrew: https://brew.sh
:uri-mise: https://mise.jdx.dev
:uri-winget: https://learn.microsoft.com/en-us/windows/package-manager/
:uri-pkl-macos-amd64-download: {uri-sonatype-snapshot-download}&a=pkl-cli-macos-amd64&e=bin
:uri-pkl-macos-aarch64-download: {uri-sonatype-snapshot-download}&a=pkl-cli-macos-aarch64&e=bin
@@ -108,31 +107,6 @@ ifndef::is-release-version[]
For instructions, switch to a release version of this page.
endif::[]
[[winget]]
=== Windows Package Manager
On Windows, release versions can be installed with {uri-winget}[Windows Package Manager].
ifdef::is-release-version[]
To install Pkl, run:
[source,shell]
----
winget install Apple.Pkl
----
To update Pkl, run:
[source,shell]
----
winget upgrade Apple.Pkl
----
endif::[]
ifndef::is-release-version[]
For instructions, switch to a release version of this page.
endif::[]
[[download]]
=== Download
@@ -733,33 +707,6 @@ pkl shell-completion bash
pkl shell-completion zsh
----
[[command-format-check]]
=== `pkl format check`
*Synopsis*: `pkl format check <file-or-dir-path>`
This command checks for format violations on the given file or directory and print their names to stdout. +
It returns a non-zero status code in case violations are found.
If the path is a directory, recursively looks for files with a `.pkl` extension, or files named `PklProject`.
[[command-format-apply]]
=== `pkl format apply`
*Synopsis*: `pkl format apply [<options>] <file-or-dir-path>`
This command formats the given files overwriting them.
If the path is a directory, recursively looks for files with a `.pkl` extension, or files named `PklProject`.
==== Options
.-s, --silent
[%collapsible]
====
Do not write the name of wrongly formatted files to stdout.
====
[[common-options]]
=== Common options
+1 -1
View File
@@ -94,7 +94,7 @@ The `pkl-doc` library is available {uri-pkl-doc-maven}[from Maven Central].
It requires Java 17 or higher.
ifndef::is-release-version[]
NOTE: Snapshots are published to repository `{uri-snapshot-repo}`.
NOTE: Snapshots are published to repository `{uri-sonatype}`.
endif::[]
==== Gradle
+1 -1
View File
@@ -25,7 +25,7 @@ It requires Java 17 or higher and Gradle 8.1 or higher.
Earlier Gradle versions are not supported.
ifndef::is-release-version[]
NOTE: Snapshots are published to repository `{uri-snapshot-repo}`.
NOTE: Snapshots are published to repository `{uri-sonatype}`.
endif::[]
The plugin is applied as follows:
+1 -1
View File
@@ -1,6 +1,6 @@
= Pkl 0.29 Release Notes
:version: 0.29
:version-minor: 0.29.1
:version-minor: 0.29.0
:release-date: July 24th, 2025
include::ROOT:partial$component-attributes.adoc[]
@@ -1,51 +0,0 @@
= Pkl 0.30 Release Notes
:version: 0.30
:version-minor: 0.30.0
:release-date: TBD
link:ROOT:partial$component-attributes.adoc[role=include]
Pkl {version} was released on {release-date}. +
[.small]#The latest bugfix release is {version-minor}. (xref:changelog.adoc[All Versions])#
The next release (0.XX) is scheduled for ???..
To see what's coming in the future, follow the {uri-pkl-roadmap}[Pkl Roadmap].
Please send feedback and questions to https://github.com/apple/pkl/discussions[GitHub Discussions], or submit an issue on https://github.com/apple/pkl/issues/new[Github]. +
[small]#Pkl is hosted on https://github.com/apple/pkl[GitHub].
To get started, follow xref:pkl-cli:index.adoc#installation[Installation].#
== Highlights [small]#💖#
News you don't want to miss.
=== XXX
== Noteworthy [small]#🎶#
Ready when you need them.
=== XXX
== Breaking Changes [small]#💔#
Things to watch out for when upgrading.
=== XXX
== Miscellaneous [small]#🐸#
* XXX
== Bugs fixed [small]#🐜#
The following bugs have been fixed.
* XXX (https://github.com/apple/pkl/issues/XXX[XXX])
== Contributors [small]#🙏#
We would like to thank the contributors to this release (in alphabetical order):
* XXX
@@ -1,29 +1,6 @@
= Changelog
include::ROOT:partial$component-attributes.adoc[]
[[release-0.30.0]]
== 0.30.0 (TBD)
[[release-0.29.1]]
== 0.29.1 (2025-08-27)
=== Fixes
* Fixes an issue where autocompletion in Bash and ZSH do noes not suggest filenames (https://github.com/apple/pkl/pull/1161[#1161]).
* Fixes an issue where `pkldoc` throws a runtime error about failing to load class path resources (https://github.com/apple/pkl/issues/1174[#1174]).
* Fixes an issue where `pkldoc` always runs with `testMode` set to true.
* Fixes an issue where evaluating a module that ends with an unmatched backtick throws `ArrayIndexOutOfBoundsException` (https://github.com/apple/pkl/issues/1182[#1182]).
* Fixes the formatting of YAML strings when emitting backslash characters within quoted strings (https://github.com/apple/pkl/pull/1165[#1165]).
* Fixes an issue where `local` members inside `Mapping` objects are incorrectly encoded into binary format (https://github.com/apple/pkl/issues/1151[#1151]).
=== Contributors ❤️
Thank you to all the contributors for this release!
* https://github.com/bioball[@bioball]
* https://github.com/gordonbondon[@gordonbondon]
* https://github.com/HT154[@HT154]
[[release-0.29.0]]
== 0.29.0 (2025-07-24)
@@ -2,8 +2,6 @@
The Pkl team aims to release a new version of Pkl in February, June, and October of each year.
* xref:0.30.adoc[0.30 Release Notes]
* xref:0.29.adoc[0.29 Release Notes]
* xref:0.28.adoc[0.28 Release Notes]
* xref:0.27.adoc[0.27 Release Notes]
* xref:0.26.adoc[0.26 Release Notes]
-1
View File
@@ -41,7 +41,6 @@
* xref:ROOT:evolution-and-roadmap.adoc[Evolution and Roadmap]
* xref:release-notes:index.adoc[Release Notes]
** xref:release-notes:0.30.adoc[0.30 Release Notes]
** xref:release-notes:0.29.adoc[0.29 Release Notes]
** xref:release-notes:0.28.adoc[0.28 Release Notes]
** xref:release-notes:0.27.adoc[0.27 Release Notes]
+1 -1
View File
@@ -1,7 +1,7 @@
# suppress inspection "UnusedProperty" for whole file
group=org.pkl-lang
version=0.30.0
version=0.29.0
# google-java-format requires jdk.compiler exports
org.gradle.jvmargs= \
+3 -3
View File
@@ -2,15 +2,15 @@
"catalogs": {},
"aliases": {
"pkl": {
"script-ref": "org.pkl-lang:pkl-cli-java:0.29.1",
"script-ref": "org.pkl-lang:pkl-cli-java:0.29.0",
"java-agents": []
},
"pkl-codegen-java": {
"script-ref": "org.pkl-lang:pkl-codegen-java:0.29.1",
"script-ref": "org.pkl-lang:pkl-codegen-java:0.29.0",
"java-agents": []
},
"pkl-codegen-kotlin": {
"script-ref": "org.pkl-lang:pkl-codegen-kotlin:0.29.1",
"script-ref": "org.pkl-lang:pkl-codegen-kotlin:0.29.0",
"java-agents": []
}
},
+8 -8
View File
@@ -49,7 +49,7 @@ org.apache.httpcomponents.client5:httpclient5:5.5=testCompileClasspath,testImple
org.apache.httpcomponents.core5:httpcore5-h2:5.3.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apache.httpcomponents.core5:httpcore5:5.3.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata
org.assertj:assertj-core:3.27.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.eclipse.jetty.http2:http2-common:11.0.24=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.eclipse.jetty.http2:http2-hpack:11.0.24=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.eclipse.jetty.http2:http2-server:11.0.24=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
@@ -110,13 +110,13 @@ org.jline:jline-reader:3.23.0=compileClasspath,implementationDependenciesMetadat
org.jline:jline-terminal-jansi:3.23.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jline:jline-terminal:3.23.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jspecify:jspecify:1.0.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.4=testRuntimeClasspath
org.junit:junit-bom:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.3=testRuntimeClasspath
org.junit:junit-bom:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.msgpack:msgpack-core:0.9.8=runtimeClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.organicdesign:Paguro:3.10.3=runtimeClasspath,testRuntimeClasspath
-1
View File
@@ -61,7 +61,6 @@ dependencies {
implementation(libs.jlineTerminal)
implementation(libs.jlineTerminalJansi)
implementation(projects.pklServer)
implementation(projects.pklFormatter)
implementation(libs.clikt)
testImplementation(projects.pklCommonsTest)
@@ -1,54 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.cli
import java.io.IOException
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.writeText
import org.pkl.commons.cli.CliBaseOptions
import org.pkl.commons.cli.CliException
class CliFormatterApply(cliBaseOptions: CliBaseOptions, path: Path, private val silent: Boolean) :
CliFormatterCommand(cliBaseOptions, path) {
override fun doRun() {
var status = 0
for (path in paths()) {
val contents = Files.readString(path)
val (formatted, stat) = format(path, contents)
status = if (status == 0) stat else status
if (stat != 0 || contents == formatted) continue
if (!silent) {
consoleWriter.write(path.toAbsolutePath().toString())
consoleWriter.appendLine()
consoleWriter.flush()
}
try {
path.writeText(formatted, Charsets.UTF_8)
} catch (e: IOException) {
consoleWriter.write("Could not overwrite `$path`: ${e.message}")
consoleWriter.appendLine()
consoleWriter.flush()
status = 1
}
}
if (status != 0) {
throw CliException("Formatting violations found.", status)
}
}
}
@@ -1,44 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.cli
import java.nio.file.Files
import java.nio.file.Path
import org.pkl.commons.cli.CliBaseOptions
import org.pkl.commons.cli.CliException
class CliFormatterCheck(cliBaseOptions: CliBaseOptions, path: Path) :
CliFormatterCommand(cliBaseOptions, path) {
override fun doRun() {
var status = 0
for (path in paths()) {
val contents = Files.readString(path)
val (formatted, stat) = format(path, contents)
status = if (status == 0) stat else status
if (contents != formatted) {
consoleWriter.write(path.toAbsolutePath().toString())
consoleWriter.appendLine()
consoleWriter.flush()
status = 1
}
}
if (status != 0) {
throw CliException("Formatting violations found.", status)
}
}
}
@@ -1,54 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.cli
import java.io.Writer
import java.nio.file.Path
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.extension
import kotlin.io.path.isDirectory
import kotlin.io.path.name
import kotlin.io.path.walk
import org.pkl.commons.cli.CliBaseOptions
import org.pkl.commons.cli.CliCommand
import org.pkl.formatter.Formatter
import org.pkl.parser.GenericParserError
abstract class CliFormatterCommand
@JvmOverloads
constructor(
options: CliBaseOptions,
protected val path: Path,
protected val consoleWriter: Writer = System.out.writer(),
) : CliCommand(options) {
protected fun format(file: Path, contents: String): Pair<String, Int> {
try {
return Formatter().format(contents) to 0
} catch (pe: GenericParserError) {
consoleWriter.write("Could not format `$file`: $pe")
consoleWriter.appendLine()
consoleWriter.flush()
return "" to 1
}
}
@OptIn(ExperimentalPathApi::class)
protected fun paths(): Sequence<Path> {
return if (path.isDirectory()) {
path.walk().filter { it.extension == "pkl" || it.name == "PklProject" }
} else sequenceOf(path)
}
}
@@ -15,7 +15,6 @@
*/
package org.pkl.cli.commands
import com.github.ajalt.clikt.completion.CompletionCandidates
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.flag
import com.github.ajalt.clikt.parameters.options.option
@@ -34,7 +33,6 @@ class EvalCommand : ModulesCommand(name = "eval", helpLink = helpLink) {
names = arrayOf("-o", "--output-path"),
metavar = "path",
help = "File path where the output file is placed.",
completionCandidates = CompletionCandidates.Path,
)
.single()
@@ -61,7 +59,6 @@ class EvalCommand : ModulesCommand(name = "eval", helpLink = helpLink) {
names = arrayOf("-m", "--multiple-file-output-path"),
metavar = "path",
help = "Directory where a module's multiple file output is placed.",
completionCandidates = CompletionCandidates.Path,
)
.single()
.validate {
@@ -1,71 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.cli.commands
import com.github.ajalt.clikt.core.Context
import com.github.ajalt.clikt.core.NoOpCliktCommand
import com.github.ajalt.clikt.core.subcommands
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.options.flag
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.types.path
import java.nio.file.Path
import org.pkl.cli.CliFormatterApply
import org.pkl.cli.CliFormatterCheck
import org.pkl.commons.cli.commands.BaseCommand
class FormatterCommand : NoOpCliktCommand(name = "format") {
override fun help(context: Context) = "Run commands related to formatting"
override fun helpEpilog(context: Context) = "For more information, visit $helpLink"
init {
subcommands(FormatterCheckCommand(), FormatterApplyCommand())
}
}
class FormatterCheckCommand : BaseCommand(name = "check", helpLink = helpLink) {
override val helpString: String =
"Check if the given files are properly formatted, printing the file name to stdout in case they are not. Returns non-zero in case of failure."
val path: Path by
argument(name = "path", help = "File or directory to check.")
.path(mustExist = true, canBeDir = true)
override fun run() {
CliFormatterCheck(baseOptions.baseOptions(emptyList()), path).run()
}
}
class FormatterApplyCommand : BaseCommand(name = "apply", helpLink = helpLink) {
override val helpString: String =
"Overwrite all the files in place with the formatted version. Returns non-zero in case of failure."
val path: Path by
argument(name = "path", help = "File or directory to format.")
.path(mustExist = true, canBeDir = true)
val silent: Boolean by
option(
names = arrayOf("-s", "--silent"),
help = "Do not write the name of the files that failed formatting to stdout.",
)
.flag()
override fun run() {
CliFormatterApply(baseOptions.baseOptions(emptyList()), path, silent).run()
}
}
@@ -15,7 +15,6 @@
*/
package org.pkl.cli.commands
import com.github.ajalt.clikt.completion.CompletionCandidates
import com.github.ajalt.clikt.core.Context
import com.github.ajalt.clikt.core.NoOpCliktCommand
import com.github.ajalt.clikt.core.subcommands
@@ -117,7 +116,6 @@ class PackageCommand : BaseCommand(name = "package", helpLink = helpLink) {
names = arrayOf("--output-path"),
help = "The directory to write artifacts to",
metavar = "path",
completionCandidates = CompletionCandidates.Path,
)
.single()
.default(".out/%{name}@%{version}")
@@ -49,7 +49,6 @@ class RootCommand : NoOpCliktCommand(name = "pkl") {
ProjectCommand(),
DownloadPackageCommand(),
AnalyzeCommand(),
FormatterCommand(),
CompletionCommand(
name = "shell-completion",
help = "Generate a completion script for the given shell",
@@ -15,7 +15,6 @@
*/
package org.pkl.cli.commands
import com.github.ajalt.clikt.completion.CompletionCandidates
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.arguments.convert
import com.github.ajalt.clikt.parameters.arguments.multiple
@@ -31,11 +30,7 @@ class TestCommand : BaseCommand(name = "test", helpLink = helpLink) {
override val helpString = "Run tests within the given module(s)"
val modules: List<URI> by
argument(
name = "modules",
help = "Module paths or URIs to evaluate.",
completionCandidates = CompletionCandidates.Path,
)
argument(name = "modules", help = "Module paths or URIs to evaluate.")
.convert { BaseOptions.parseModuleName(it) }
.multiple()
@@ -52,7 +52,6 @@ internal class Repl(workingDir: Path, private val server: ReplServer) {
private var continuation = false
private var quit = false
private var maybeQuit = false
private var nextRequestId = 0
fun run() {
@@ -75,23 +74,11 @@ internal class Repl(workingDir: Path, private val server: ReplServer) {
reader.readLine("pkl$nextRequestId> ")
}
} catch (e: UserInterruptException) {
if (!continuation && reader.buffer.length() == 0) {
if (maybeQuit) quit()
else {
maybeQuit = true
println("(To exit, press ^C again or ^D or type :quit)")
}
} else {
maybeQuit = false
}
inputBuffer = ""
continuation = false
continue
":quit"
} catch (e: EndOfFileException) {
":quit"
}
maybeQuit = false
val input = line.trim()
if (input.isEmpty()) continue
@@ -1,5 +1,5 @@
/*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024 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.
@@ -64,11 +64,4 @@ class ReplMessagesTest {
startIndex = examples.indexOf("```", endIndex + 3)
}
}
@Test
fun `handle single backtick`() {
val responses = server.handleRequest(ReplRequest.Eval("1", "`", true, true))
assertThat(responses.size).isEqualTo(1)
assertThat(responses).hasOnlyElementsOfType(ReplResponse.EvalError::class.java)
}
}
+8 -8
View File
@@ -26,7 +26,7 @@ io.leangen.geantyref:geantyref:1.3.16=testRuntimeClasspath
net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.java.dev.jna:jna:5.14.0=runtimeClasspath,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata
org.assertj:assertj-core:3.27.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.polyglot:polyglot:24.1.2=runtimeClasspath,testRuntimeClasspath
org.graalvm.sdk:collections:24.1.2=runtimeClasspath,testRuntimeClasspath
org.graalvm.sdk:graal-sdk:24.1.2=runtimeClasspath,testRuntimeClasspath
@@ -56,13 +56,13 @@ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClass
org.jetbrains:annotations:13.0=compileClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jetbrains:markdown-jvm:0.7.3=runtimeClasspath,testRuntimeClasspath
org.jetbrains:markdown:0.7.3=runtimeClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.4=testRuntimeClasspath
org.junit:junit-bom:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.3=testRuntimeClasspath
org.junit:junit-bom:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.msgpack:msgpack-core:0.9.8=runtimeClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.organicdesign:Paguro:3.10.3=runtimeClasspath,testRuntimeClasspath
+8 -8
View File
@@ -26,7 +26,7 @@ io.leangen.geantyref:geantyref:1.3.16=testRuntimeClasspath
net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.java.dev.jna:jna:5.14.0=runtimeClasspath,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata
org.assertj:assertj-core:3.27.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.polyglot:polyglot:24.1.2=runtimeClasspath,testRuntimeClasspath
org.graalvm.sdk:collections:24.1.2=runtimeClasspath,testRuntimeClasspath
org.graalvm.sdk:graal-sdk:24.1.2=runtimeClasspath,testRuntimeClasspath
@@ -58,13 +58,13 @@ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClass
org.jetbrains:annotations:13.0=compileClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jetbrains:markdown-jvm:0.7.3=runtimeClasspath,testRuntimeClasspath
org.jetbrains:markdown:0.7.3=runtimeClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.4=testRuntimeClasspath
org.junit:junit-bom:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.3=testRuntimeClasspath
org.junit:junit-bom:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.msgpack:msgpack-core:0.9.8=runtimeClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.organicdesign:Paguro:3.10.3=runtimeClasspath,testRuntimeClasspath
+8 -8
View File
@@ -24,7 +24,7 @@ com.github.ajalt.mordant:mordant:3.0.1=apiDependenciesMetadata,compileClasspath,
net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.java.dev.jna:jna:5.14.0=runtimeClasspath,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata
org.assertj:assertj-core:3.27.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.compiler:compiler:24.1.2=svmClasspath
org.graalvm.nativeimage:native-image-base:24.1.2=svmClasspath
org.graalvm.nativeimage:objectfile:24.1.2=svmClasspath
@@ -63,13 +63,13 @@ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClass
org.jetbrains:annotations:13.0=compileClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathSvm,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jetbrains:markdown-jvm:0.7.3=runtimeClasspath,testRuntimeClasspath
org.jetbrains:markdown:0.7.3=implementationDependenciesMetadata,runtimeClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.4=testRuntimeClasspath
org.junit:junit-bom:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.3=testRuntimeClasspath
org.junit:junit-bom:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.msgpack:msgpack-core:0.9.8=runtimeClasspath,svmClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.organicdesign:Paguro:3.10.3=runtimeClasspath,svmClasspath,testRuntimeClasspath
@@ -218,9 +218,8 @@ abstract class CliCommand(protected val cliOptions: CliBaseOptions) {
}
if (!certsAdded) {
val defaultCerts =
this@CliCommand.javaClass.classLoader.getResourceAsStream(
"org/pkl/commons/cli/PklCARoots.pem"
) ?: throw CliException("Could not find bundled certificates")
javaClass.classLoader.getResourceAsStream("org/pkl/commons/cli/PklCARoots.pem")
?: throw CliException("Could not find bundled certificates")
addCertificates(defaultCerts.readAllBytes())
}
}
@@ -15,7 +15,6 @@
*/
package org.pkl.commons.cli.commands
import com.github.ajalt.clikt.completion.CompletionCandidates
import com.github.ajalt.clikt.parameters.groups.OptionGroup
import com.github.ajalt.clikt.parameters.options.*
import com.github.ajalt.clikt.parameters.types.enum
@@ -166,7 +165,6 @@ class BaseOptions : OptionGroup() {
option(
names = arrayOf("-f", "--format"),
help = "Output format to generate. <${output.joinToString()}>",
completionCandidates = CompletionCandidates.Fixed(output.toSet()),
)
.single()
@@ -189,13 +187,9 @@ class BaseOptions : OptionGroup() {
.splitAll(File.pathSeparator)
val settings: URI? by
option(
names = arrayOf("--settings"),
help = "Pkl settings module to use.",
completionCandidates = CompletionCandidates.Path,
)
.single()
.convert { parseModuleName(it) }
option(names = arrayOf("--settings"), help = "Pkl settings module to use.").single().convert {
parseModuleName(it)
}
val timeout: Duration? by
option(
@@ -15,7 +15,6 @@
*/
package org.pkl.commons.cli.commands
import com.github.ajalt.clikt.completion.CompletionCandidates
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.arguments.convert
import com.github.ajalt.clikt.parameters.arguments.multiple
@@ -25,11 +24,7 @@ import java.net.URI
abstract class ModulesCommand(name: String, helpLink: String) :
BaseCommand(name = name, helpLink = helpLink) {
open val modules: List<URI> by
argument(
name = "modules",
help = "Module paths or URIs to evaluate.",
completionCandidates = CompletionCandidates.Path,
)
argument(name = "modules", help = "Module paths or URIs to evaluate.")
.convert { BaseOptions.parseModuleName(it) }
.multiple(required = true)
+8 -8
View File
@@ -3,7 +3,7 @@
# This file is expected to be part of source control.
net.bytebuddy:byte-buddy:1.15.11=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,testCompileClasspath,testImplementationDependenciesMetadata
org.assertj:assertj-core:3.27.4=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.assertj:assertj-core:3.27.3=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-build-common:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-build-tools-api:2.0.21=kotlinBuildToolsApiClasspath
@@ -25,12 +25,12 @@ org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21=apiDependenciesMetadata,compileCl
org.jetbrains.kotlin:kotlin-stdlib:2.0.21=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains:annotations:13.0=compileClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.4=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.4=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.4=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.4=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.4=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.4=testRuntimeClasspath
org.junit:junit-bom:5.13.4=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.3=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.3=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.3=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.3=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.3=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.3=testRuntimeClasspath
org.junit:junit-bom:5.13.3=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
empty=annotationProcessor,compileOnlyDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDefExtensions,sourcesJar,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDefExtensions
@@ -1,85 +0,0 @@
/*
* Copyright © 2024-2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.commons.test
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.exists
import org.pkl.commons.test.FileTestUtils.rootProjectDir
sealed class ExecutablePaths(protected val gradleProject: String) {
abstract val allNative: List<Path>
val existingNative: List<Path>
get() = allNative.filter(Files::exists)
val firstExistingNative: Path
get() =
existingNative.firstOrNull()
?: throw AssertionError(
"Native executable not found on system. " +
"To fix this problem, run `./gradlew $gradleProject:assembleNative`."
)
protected fun executable(name: String): Path =
rootProjectDir.resolve("$gradleProject/build/executable").resolve(name)
protected fun javaExecutable(name: String): Path {
val isWindows = System.getProperty("os.name").startsWith("Windows")
val effectiveName = if (isWindows) "$name.bat" else name
return rootProjectDir.resolve("$gradleProject/build/executable").resolve(effectiveName).also {
path ->
if (!path.exists()) {
throw AssertionError(
"Java executable not found on system. " +
"To fix this problem, run `./gradlew $gradleProject:javaExecutable`."
)
}
}
}
}
@Suppress("ClassName")
object Executables {
object pkl : ExecutablePaths("pkl-cli") {
val macAarch64: Path = executable("pkl-macos-aarch64")
val macAmd64: Path = executable("pkl-macos-amd64")
val linuxAarch64: Path = executable("pkl-linux-aarch64")
val linuxAmd64: Path = executable("pkl-linux-amd64")
val alpineAmd64: Path = executable("pkl-alpine-linux-amd64")
val windowsAmd64: Path = executable("pkl-windows-amd64.exe")
// order (aarch64 before amd64, linux before alpine) affects [firstExisting]
override val allNative: List<Path> =
listOf(macAarch64, macAmd64, linuxAarch64, linuxAmd64, alpineAmd64, windowsAmd64)
}
object pkldoc : ExecutablePaths("pkl-doc") {
val macAarch64: Path = executable("pkldoc-macos-aarch64")
val macAmd64: Path = executable("pkldoc-macos-amd64")
val linuxAarch64: Path = executable("pkldoc-linux-aarch64")
val linuxAmd64: Path = executable("pkldoc-linux-amd64")
val alpineAmd64: Path = executable("pkldoc-alpine-linux-amd64")
val windowsAmd64: Path = executable("pkldoc-windows-amd64.exe")
val javaExecutable: Path by lazy { javaExecutable("jpkldoc") }
// order (aarch64 before amd64, linux before alpine) affects [firstExisting]
override val allNative: List<Path> =
listOf(macAarch64, macAmd64, linuxAarch64, linuxAmd64, alpineAmd64, windowsAmd64)
}
}
@@ -0,0 +1,47 @@
/*
* Copyright © 2024 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.commons.test
import java.nio.file.Files
import java.nio.file.Path
import org.pkl.commons.test.FileTestUtils.rootProjectDir
object PklExecutablePaths {
val macAarch64: Path = executablePath("pkl-macos-aarch64")
val macAmd64: Path = executablePath("pkl-macos-amd64")
val linuxAarch64: Path = executablePath("pkl-linux-aarch64")
val linuxAmd64: Path = executablePath("pkl-linux-amd64")
val alpineAmd64: Path = executablePath("pkl-alpine-linux-amd64")
val windowsAmd64: Path = executablePath("pkl-windows-amd64.exe")
// order (aarch64 before amd64, linux before alpine) affects [firstExisting]
val all: List<Path> =
listOf(macAarch64, macAmd64, linuxAarch64, linuxAmd64, alpineAmd64, windowsAmd64)
val existing: List<Path>
get() = all.filter(Files::exists)
val firstExisting: Path
get() =
existing.firstOrNull()
?: throw AssertionError(
"Native executable not found on system. " +
"To fix this problem, run `./gradlew assembleNative`."
)
private fun executablePath(name: String): Path =
rootProjectDir.resolve("pkl-cli/build/executable").resolve(name)
}
+8 -8
View File
@@ -3,7 +3,7 @@
# This file is expected to be part of source control.
net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata
org.assertj:assertj-core:3.27.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-build-common:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-build-tools-api:2.0.21=kotlinBuildToolsApiClasspath
@@ -25,12 +25,12 @@ org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21=apiDependenciesMetadata,compileCl
org.jetbrains.kotlin:kotlin-stdlib:2.0.21=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains:annotations:13.0=compileClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.4=testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.4=testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.4=testRuntimeClasspath
org.junit:junit-bom:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.3=testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.3=testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.3=testRuntimeClasspath
org.junit:junit-bom:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
empty=annotationProcessor,compileOnlyDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDefExtensions,signatures,sourcesJar,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDefExtensions
+8 -8
View File
@@ -27,7 +27,7 @@ javax.inject:javax.inject:1=testCompileClasspath,testImplementationDependenciesM
net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.java.dev.jna:jna:5.14.0=pklCodegenJava
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata
org.assertj:assertj-core:3.27.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.polyglot:polyglot:24.1.2=pklCodegenJava,runtimeClasspath,testRuntimeClasspath
org.graalvm.sdk:collections:24.1.2=pklCodegenJava,runtimeClasspath,testRuntimeClasspath
org.graalvm.sdk:graal-sdk:24.1.2=pklCodegenJava,runtimeClasspath,testRuntimeClasspath
@@ -57,13 +57,13 @@ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClass
org.jetbrains:annotations:13.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,pklCodegenJava,testCompileClasspath,testRuntimeClasspath
org.jetbrains:markdown-jvm:0.7.3=pklCodegenJava
org.jetbrains:markdown:0.7.3=pklCodegenJava
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.4=testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.4=testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.4=testRuntimeClasspath
org.junit:junit-bom:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.3=testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.3=testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.3=testRuntimeClasspath
org.junit:junit-bom:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.msgpack:msgpack-core:0.9.8=pklCodegenJava,runtimeClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.organicdesign:Paguro:3.10.3=pklCodegenJava,runtimeClasspath,testRuntimeClasspath
+8 -8
View File
@@ -26,7 +26,7 @@ io.leangen.geantyref:geantyref:1.3.16=pklConfigJava,runtimeClasspath,testCompile
net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.java.dev.jna:jna:5.14.0=pklCodegenKotlin
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata
org.assertj:assertj-core:3.27.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.polyglot:polyglot:24.1.2=pklCodegenKotlin,pklConfigJava,runtimeClasspath,testRuntimeClasspath
org.graalvm.sdk:collections:24.1.2=pklCodegenKotlin,pklConfigJava,runtimeClasspath,testRuntimeClasspath
org.graalvm.sdk:graal-sdk:24.1.2=pklCodegenKotlin,pklConfigJava,runtimeClasspath,testRuntimeClasspath
@@ -56,13 +56,13 @@ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClass
org.jetbrains:annotations:13.0=compileClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,pklCodegenKotlin,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jetbrains:markdown-jvm:0.7.3=pklCodegenKotlin
org.jetbrains:markdown:0.7.3=pklCodegenKotlin
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.4=testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.4=testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.4=testRuntimeClasspath
org.junit:junit-bom:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.3=testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.3=testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.3=testRuntimeClasspath
org.junit:junit-bom:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.msgpack:msgpack-core:0.9.8=pklCodegenKotlin,pklConfigJava,runtimeClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.organicdesign:Paguro:3.10.3=pklCodegenKotlin,pklConfigJava,runtimeClasspath,testRuntimeClasspath
+8 -8
View File
@@ -5,7 +5,7 @@ com.google.code.findbugs:jsr305:3.0.2=compileClasspath,compileOnlyDependenciesMe
com.palantir.javapoet:javapoet:0.7.0=generatorCompileClasspath,generatorImplementationDependenciesMetadata,generatorRuntimeClasspath
net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata
org.assertj:assertj-core:3.27.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.polyglot:polyglot:24.1.2=compileClasspath,generatorCompileClasspath,generatorImplementationDependenciesMetadata,generatorRuntimeClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.sdk:collections:24.1.2=compileClasspath,generatorCompileClasspath,generatorImplementationDependenciesMetadata,generatorRuntimeClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.sdk:graal-sdk:24.1.2=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
@@ -34,13 +34,13 @@ org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21=generatorCompileClasspath,generat
org.jetbrains.kotlin:kotlin-stdlib:2.0.21=generatorCompileClasspath,generatorImplementationDependenciesMetadata,generatorRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathGenerator,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains:annotations:13.0=generatorCompileClasspath,generatorRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathGenerator,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.4=testRuntimeClasspath
org.junit:junit-bom:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.3=testRuntimeClasspath
org.junit:junit-bom:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.msgpack:msgpack-core:0.9.8=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.organicdesign:Paguro:3.10.3=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
@@ -33,7 +33,7 @@ import org.pkl.parser.syntax.Module;
@TruffleLanguage.Registration(
id = "pkl",
name = "Pkl",
version = "0.30.0-dev",
version = "0.29.0",
characterMimeTypes = VmLanguage.MIME_TYPE,
contextPolicy = ContextPolicy.SHARED)
public final class VmLanguage extends TruffleLanguage<VmContext> {
@@ -1,5 +1,5 @@
/*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024 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,7 +17,6 @@ package org.pkl.core.runtime;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.MaterializedFrame;
import java.util.HashSet;
import java.util.Map;
import javax.annotation.concurrent.GuardedBy;
import org.graalvm.collections.UnmodifiableEconomicMap;
@@ -26,10 +25,10 @@ import org.pkl.core.ast.member.ObjectMember;
import org.pkl.core.util.CollectionUtils;
import org.pkl.core.util.EconomicMaps;
import org.pkl.core.util.LateInit;
import org.pkl.core.util.MutableLong;
public final class VmMapping extends VmListingOrMapping {
private long cachedLength = -1;
private int cachedEntryCount = -1;
@GuardedBy("this")
private @LateInit VmSet __allKeys;
@@ -125,7 +124,7 @@ public final class VmMapping extends VmListingOrMapping {
// could use shallow force, but deep force is cached
force(false);
other.force(false);
if (getLength() != other.getLength()) return false;
if (getEntryCount() != other.getEntryCount()) return false;
var cursor = cachedValues.getEntries();
while (cursor.advance()) {
@@ -163,21 +162,16 @@ public final class VmMapping extends VmListingOrMapping {
return result;
}
@TruffleBoundary
public long getLength() {
if (cachedLength != -1) return cachedLength;
var count = new MutableLong(0);
var visited = new HashSet<>();
iterateMembers(
(key, member) -> {
var alreadyVisited = !visited.add(key);
// important to record hidden member as visited before skipping it
// because any overriding member won't carry a `hidden` identifier
if (alreadyVisited || member.isLocalOrExternalOrHidden()) return true;
count.getAndIncrement();
return true;
});
cachedLength = count.get();
return cachedLength;
// assumes mapping has been forced
public int getEntryCount() {
if (cachedEntryCount != -1) return cachedEntryCount;
var result = 0;
for (var key : cachedValues.getKeys()) {
if (key instanceof Identifier) continue;
result += 1;
}
cachedEntryCount = result;
return result;
}
}
@@ -18,6 +18,7 @@ package org.pkl.core.stdlib.base;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.IndirectCallNode;
import java.util.HashSet;
import org.pkl.core.ast.lambda.ApplyVmFunction1Node;
import org.pkl.core.ast.lambda.ApplyVmFunction2Node;
import org.pkl.core.ast.lambda.ApplyVmFunction2NodeGen;
@@ -30,6 +31,7 @@ import org.pkl.core.stdlib.ExternalMethod2Node;
import org.pkl.core.stdlib.ExternalPropertyNode;
import org.pkl.core.util.EconomicMaps;
import org.pkl.core.util.MutableBoolean;
import org.pkl.core.util.MutableLong;
import org.pkl.core.util.MutableReference;
public final class MappingNodes {
@@ -51,8 +53,20 @@ public final class MappingNodes {
public abstract static class length extends ExternalPropertyNode {
@Specialization
@TruffleBoundary
protected long eval(VmMapping self) {
return self.getLength();
var count = new MutableLong(0);
var visited = new HashSet<>();
self.iterateMembers(
(key, member) -> {
var alreadyVisited = !visited.add(key);
// important to record hidden member as visited before skipping it
// because any overriding member won't carry a `hidden` identifier
if (alreadyVisited || member.isLocalOrExternalOrHidden()) return true;
count.getAndIncrement();
return true;
});
return count.get();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024 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.
@@ -19,55 +19,33 @@ import org.pkl.core.util.AbstractCharEscaper;
import org.pkl.core.util.IoUtils;
import org.pkl.core.util.Nullable;
/**
* Emits escape sequences for YAML. This is only used when emitting double-quoted strings.
*
* <p>Note: we don't need to escape space ({@code 0x20}) because we don't generate quoted multiline
* strings. We also don't need to escape forward slash ({@code 0x2f}) because a normal forward slash
* is also valid YAML.
*
* @see <a
* href="https://yaml.org/spec/1.2.2/#57-escaped-characters">https://yaml.org/spec/1.2.2/#57-escaped-characters</a>
*/
// https://yaml.org/spec/1.2.2/#57-escaped-characters
public final class YamlEscaper extends AbstractCharEscaper {
private static final String[] REPLACEMENTS;
static {
REPLACEMENTS = new String[0xA0 + 1];
REPLACEMENTS = new String[0x22 + 1];
for (var i = 0; i < 0x20; i++) {
REPLACEMENTS[i] = IoUtils.toHexEscape(i);
}
// ns-esc-null
REPLACEMENTS[0x00] = "\\0";
// ns-esc-bell
REPLACEMENTS[0x07] = "\\a";
// ns-esc-backspace
REPLACEMENTS[0x08] = "\\b";
// ns-esc-horizontal-tab
REPLACEMENTS[0x09] = "\\t";
// ns-esc-line-feed
REPLACEMENTS[0x0A] = "\\n";
// ns-esc-vertical-tab
REPLACEMENTS[0x0B] = "\\v";
// ns-esc-form-feed
REPLACEMENTS[0x0C] = "\\f";
// ns-esc-carriage-return
REPLACEMENTS[0x0D] = "\\r";
// ns-esc-escape
REPLACEMENTS[0x1B] = "\\e";
// ns-esc-double-quote
// we don't ever need to escape 0x20 because we don't generate quoted multiline strings
REPLACEMENTS[0x22] = "\\\"";
// ns-esc-backslash
REPLACEMENTS[0x5c] = "\\\\";
// ns-esc-next-line
REPLACEMENTS[0x85] = "\\N";
// ns-esc-non-breaking-space
REPLACEMENTS[0xA0] = "\\_";
}
@Override
protected @Nullable String findReplacement(char ch) {
//noinspection UnnecessaryUnicodeEscape
return ch <= 0xA0 ? REPLACEMENTS[ch] : ch == '\u2028' ? "\\L" : ch == '\u2029' ? "\\P" : null;
return ch <= '\u0022'
? REPLACEMENTS[ch]
: ch == '\u2028' ? "\\L" : ch == '\u2029' ? "\\P" : null;
}
}
@@ -1,36 +0,0 @@
// test escaping in double quotes
// every string is prefixed with `\t` s.t. YamlRenderer will emit double-quoted strings.
`null` = "\t\u{00}"
bell = "\t\u{7}"
backspace = "\t\u{8}"
horizontalTab = "\t"
lineFeed = "\t\u{a}"
verticalTab = "\t\u{b}"
formFeed = "\t\u{c}"
carriageReturn = "\t\r"
escape = "\t\u{1b}"
doubleQuote = "\t\""
backslash = "\t\\"
nextLine = "\t\u{85}"
nbsp = "\t\u{a0}"
lineSep = "\t\u{2028}"
paragraphSep = "\t\u{2029}"
output {
renderer = new YamlRenderer {}
}
@@ -114,12 +114,12 @@ examples {
render(".NAN")
render(".nAn") // never float
}
["tag like strings"] {
"!!bool true"
"!!str my string value"
}
["number like string keys"] {
render(new Dynamic {
`0` = "0"
@@ -1 +0,0 @@
`
@@ -1,9 +0,0 @@
res1: Int(isEven, isNonZero, isBetween(-10, 10), ) = 6
res2: Int(
isEven, isNonZero, isBetween(-10, 10),
) = 6
res3: Int(
isEven,
isNonZero,
isBetween(-10, 10),
) = 6
@@ -1,43 +0,0 @@
local lA1 = (a, b, c,) -> true
local lA2 = (
a, b, c,
) -> true
local lA3 = (
a,
b,
c,
) -> true
local lB1 = (a: Int, b: Int, c: Int,) -> true
local lB2 = (
a: Int, b: Int, c: Int,
) -> true
local lB3 = (
a: Int,
b: Int,
c: Int,
) -> true
local lC1: (Dynamic,) -> Dynamic = new Mixin { a, -> x = true }
local lC2: (Dynamic,) -> Dynamic = new Mixin { a, ->
x = true
}
local lC3: (Dynamic,) -> Dynamic = new Mixin {
a, -> x = true
}
local lC4: (Dynamic,) -> Dynamic = new Mixin {
a, ->
x = true
}
local lD1: (Dynamic,) -> Dynamic = new Mixin { a: Dynamic, -> x = true }
local lD2: (Dynamic,) -> Dynamic = new Mixin { a: Dynamic, ->
x = true
}
local lD3: (Dynamic,) -> Dynamic = new Mixin {
a: Dynamic, -> x = true
}
local lD4: (Dynamic,) -> Dynamic = new Mixin {
a: Dynamic, ->
x = true
}
@@ -1,157 +0,0 @@
function moduleMethodA1(a, b, c, ) = true
function moduleMethodA2(
a, b, c,
) = true
function moduleMethodA3(
a,
b,
c,
) = true
function moduleMethodB1(a: Int, b: Int, c: Int, ) = true
function moduleMethodB2(
a: Int, b: Int, c: Int,
) = true
function moduleMethodB3(
a: Int,
b: Int,
c: Int,
) = true
class A {
function classMethodA1(a, b, c, ) = true
function classMethodA2(
a, b, c,
) = true
function classMethodA3(
a,
b,
c,
) = true
function classMethodB1(a: Int, b: Int, c: Int, ) = true
function classMethodB2(
a: Int, b: Int, c: Int,
) = true
function classMethodB3(
a: Int,
b: Int,
c: Int,
) = true
}
moduleMethodA1Call1 = moduleMethodA1(1, 2, 3, )
moduleMethodA1Call2 = moduleMethodA1(
1, 2, 3,
)
moduleMethodA1Call3 = moduleMethodA1(
1,
2,
3,
)
moduleMethodA2Call1 = moduleMethodA2(1, 2, 3, )
moduleMethodA2Call2 = moduleMethodA2(
1, 2, 3,
)
moduleMethodA2Call3 = moduleMethodA2(
1,
2,
3,
)
moduleMethodA3Call1 = moduleMethodA3(1, 2, 3, )
moduleMethodA3Call2 = moduleMethodA3(
1, 2, 3,
)
moduleMethodA3Call3 = moduleMethodA3(
1,
2,
3,
)
moduleMethodB1Call1 = moduleMethodB1(1, 2, 3, )
moduleMethodB1Call2 = moduleMethodB1(
1, 2, 3,
)
moduleMethodB1Call3 = moduleMethodB1(
1,
2,
3,
)
moduleMethodB2Call1 = moduleMethodB2(1, 2, 3, )
moduleMethodB2Call2 = moduleMethodB2(
1, 2, 3,
)
moduleMethodB2Call3 = moduleMethodB2(
1,
2,
3,
)
moduleMethodB3Call1 = moduleMethodB3(1, 2, 3, )
moduleMethodB3Call2 = moduleMethodB3(
1, 2, 3,
)
moduleMethodB3Call3 = moduleMethodB3(
1,
2,
3,
)
local a: A = new {}
classMethodA1Call1 = a.classMethodA1(1, 2, 3, )
classMethodA1Call2 = a.classMethodA1(
1, 2, 3,
)
classMethodA1Call3 = a.classMethodA1(
1,
2,
3,
)
classMethodA2Call1 = a.classMethodA2(1, 2, 3, )
classMethodA2Call2 = a.classMethodA2(
1, 2, 3,
)
classMethodA2Call3 = a.classMethodA2(
1,
2,
3,
)
classMethodA3Call1 = a.classMethodA3(1, 2, 3, )
classMethodA3Call2 = a.classMethodA3(
1, 2, 3,
)
classMethodA3Call3 = a.classMethodA3(
1,
2,
3,
)
classMethodB1Call1 = a.classMethodB1(1, 2, 3, )
classMethodB1Call2 = a.classMethodB1(
1, 2, 3,
)
classMethodB1Call3 = a.classMethodB1(
1,
2,
3,
)
classMethodB2Call1 = a.classMethodB2(1, 2, 3, )
classMethodB2Call2 = a.classMethodB2(
1, 2, 3,
)
classMethodB2Call3 = a.classMethodB2(
1,
2,
3,
)
classMethodB3Call1 = a.classMethodB3(1, 2, 3, )
classMethodB3Call2 = a.classMethodB3(
1, 2, 3,
)
classMethodB3Call3 = a.classMethodB3(
1,
2,
3,
)
@@ -1,3 +0,0 @@
res1: Mapping<String, String,>(!isEmpty) = new Mapping<String, String,> {
["hello"] = "world"
}
File diff suppressed because it is too large Load Diff
@@ -1,15 +0,0 @@
'null': "\t\0"
bell: "\t\a"
backspace: "\t\b"
horizontalTab: "\t"
lineFeed: "\t\n"
verticalTab: "\t\v"
formFeed: "\t\f"
carriageReturn: "\t\r"
escape: "\t\e"
doubleQuote: "\t\""
backslash: "\t\\"
nextLine: "\t\N"
nbsp: "\t\_"
lineSep: "\t\L"
paragraphSep: "\t\P"
@@ -1,7 +0,0 @@
–– Pkl Error ––
Unexpected character `
`. Did you mean `backquote`?
x | `
^
at singleBacktick (file:///$snippetsDir/input/errors/singleBacktick.pkl)
@@ -1,3 +0,0 @@
res1 = 6
res2 = 6
res3 = 6
@@ -1,36 +0,0 @@
moduleMethodA1Call1 = true
moduleMethodA1Call2 = true
moduleMethodA1Call3 = true
moduleMethodA2Call1 = true
moduleMethodA2Call2 = true
moduleMethodA2Call3 = true
moduleMethodA3Call1 = true
moduleMethodA3Call2 = true
moduleMethodA3Call3 = true
moduleMethodB1Call1 = true
moduleMethodB1Call2 = true
moduleMethodB1Call3 = true
moduleMethodB2Call1 = true
moduleMethodB2Call2 = true
moduleMethodB2Call3 = true
moduleMethodB3Call1 = true
moduleMethodB3Call2 = true
moduleMethodB3Call3 = true
classMethodA1Call1 = true
classMethodA1Call2 = true
classMethodA1Call3 = true
classMethodA2Call1 = true
classMethodA2Call2 = true
classMethodA2Call3 = true
classMethodA3Call1 = true
classMethodA3Call2 = true
classMethodA3Call3 = true
classMethodB1Call1 = true
classMethodB1Call2 = true
classMethodB1Call3 = true
classMethodB2Call1 = true
classMethodB2Call2 = true
classMethodB2Call3 = true
classMethodB3Call1 = true
classMethodB3Call2 = true
classMethodB3Call3 = true
@@ -1,3 +0,0 @@
res1 {
["hello"] = "world"
}
@@ -27,10 +27,10 @@ import org.junit.platform.engine.EngineDiscoveryRequest
import org.junit.platform.engine.TestDescriptor
import org.junit.platform.engine.UniqueId
import org.junit.platform.engine.support.descriptor.EngineDescriptor
import org.pkl.commons.test.Executables
import org.pkl.commons.test.FileTestUtils
import org.pkl.commons.test.InputOutputTestEngine
import org.pkl.commons.test.PackageServer
import org.pkl.commons.test.PklExecutablePaths
import org.pkl.core.http.HttpClient
import org.pkl.core.project.Project
import org.pkl.core.util.IoUtils
@@ -298,27 +298,27 @@ abstract class AbstractNativeLanguageSnippetTestsEngine : AbstractLanguageSnippe
}
class MacAmd64LanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
override val pklExecutablePath: Path = Executables.pkl.macAmd64
override val pklExecutablePath: Path = PklExecutablePaths.macAmd64
override val testClass: KClass<*> = MacLanguageSnippetTests::class
}
class MacAarch64LanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
override val pklExecutablePath: Path = Executables.pkl.macAarch64
override val pklExecutablePath: Path = PklExecutablePaths.macAarch64
override val testClass: KClass<*> = MacLanguageSnippetTests::class
}
class LinuxAmd64LanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
override val pklExecutablePath: Path = Executables.pkl.linuxAmd64
override val pklExecutablePath: Path = PklExecutablePaths.linuxAmd64
override val testClass: KClass<*> = LinuxLanguageSnippetTests::class
}
class LinuxAarch64LanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
override val pklExecutablePath: Path = Executables.pkl.linuxAarch64
override val pklExecutablePath: Path = PklExecutablePaths.linuxAarch64
override val testClass: KClass<*> = LinuxLanguageSnippetTests::class
}
class AlpineLanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
override val pklExecutablePath: Path = Executables.pkl.alpineAmd64
override val pklExecutablePath: Path = PklExecutablePaths.alpineAmd64
override val testClass: KClass<*> = AlpineLanguageSnippetTests::class
}
@@ -340,7 +340,7 @@ private val windowsNativeExcludedTests
)
class WindowsLanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
override val pklExecutablePath: Path = Executables.pkl.windowsAmd64
override val pklExecutablePath: Path = PklExecutablePaths.windowsAmd64
override val testClass: KClass<*> = WindowsLanguageSnippetTests::class
override val excludedTests: List<Regex>
get() = super.excludedTests + windowsNativeExcludedTests + windowsExcludedTests
@@ -1,82 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.core.parser
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.pkl.core.Evaluator
import org.pkl.parser.Parser
// tests type argument and parameter parsing with trailing commas that cannot be tested with
// snippets because these constructs are currently only allowed in the stdlib
class TrailingCommasTest {
private val evaluator = Evaluator.preconfigured()
@Test
fun `class type parameter lists parse correctly`() {
val module =
Parser()
.parseModule(
"""
class Foo<
Key,
Value,
>
class Bar<
Key,
Value,
> {
baz: Key
buzz: Value
}
"""
.trimIndent()
)
val fooClass = module.classes.find { it.name.value == "Foo" }
assertThat(fooClass).isNotNull
assertThat(fooClass!!.typeParameterList?.parameters?.first()?.identifier?.value)
.isEqualTo("Key")
assertThat(fooClass.typeParameterList?.parameters?.last()?.identifier?.value).isEqualTo("Value")
val barClass = module.classes.find { it.name.value == "Bar" }
assertThat(barClass).isNotNull
assertThat(barClass!!.typeParameterList?.parameters?.first()?.identifier?.value)
.isEqualTo("Key")
assertThat(barClass.typeParameterList?.parameters?.last()?.identifier?.value).isEqualTo("Value")
}
@Test
fun `method type parameter lists parse correctly`() {
val module =
Parser()
.parseModule(
"""
function foo<
A,
B,
>(a: A, b: B,): Value? = "\(a):\(b)"
"""
.trimIndent()
)
val fooMethod = module.methods.find { it.name.value == "foo" }
assertThat(fooMethod).isNotNull
assertThat(fooMethod!!.typeParameterList?.parameters?.first()?.identifier?.value).isEqualTo("A")
assertThat(fooMethod.typeParameterList?.parameters?.last()?.identifier?.value).isEqualTo("B")
}
}
+10 -10
View File
@@ -47,9 +47,9 @@ org.apache.httpcomponents:httpcore:4.4=validator
org.apache.logging.log4j:log4j-1.2-api:2.17.1=validator
org.apache.logging.log4j:log4j-api:2.17.1=validator
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata
org.assertj:assertj-core:3.27.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.commonmark:commonmark-ext-gfm-tables:0.25.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.commonmark:commonmark:0.25.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.commonmark:commonmark-ext-gfm-tables:0.25.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.commonmark:commonmark:0.25.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.eclipse.jetty:jetty-util-ajax:9.4.18.v20190429=validator
org.eclipse.jetty:jetty-util:9.4.18.v20190429=validator
org.graalvm.js:js-community:24.1.2=testRuntimeClasspath
@@ -99,13 +99,13 @@ org.jetbrains:annotations:13.0=compileClasspath,kotlinBuildToolsApiClasspath,kot
org.jetbrains:markdown-jvm:0.7.3=runtimeClasspath,testRuntimeClasspath
org.jetbrains:markdown:0.7.3=runtimeClasspath,testRuntimeClasspath
org.jspecify:jspecify:1.0.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.4=testRuntimeClasspath
org.junit:junit-bom:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.3=testRuntimeClasspath
org.junit:junit-bom:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.msgpack:msgpack-core:0.9.8=runtimeClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.organicdesign:Paguro:3.10.3=runtimeClasspath,testRuntimeClasspath
-25
View File
@@ -66,31 +66,6 @@ publishing {
}
}
val testNativeExecutable by
tasks.registering(Test::class) {
inputs.dir("src/test/files/DocGeneratorTest/input")
outputs.dir("src/test/files/DocGeneratorTest/output")
systemProperty("org.pkl.doc.NativeExecutableTest", "true")
include(listOf("**/NativeExecutableTest.class"))
}
val testJavaExecutable by
tasks.registering(Test::class) {
dependsOn(tasks.javaExecutable)
inputs.dir("src/test/files/DocGeneratorTest/input")
outputs.dir("src/test/files/DocGeneratorTest/output")
systemProperty("org.pkl.doc.JavaExecutableTest", "true")
include(listOf("**/JavaExecutableTest.class"))
}
tasks.check { dependsOn(testJavaExecutable) }
tasks.testNative { dependsOn(testNativeExecutable) }
tasks.withType<NativeImageBuild> { extraNativeImageArgs.add("-H:IncludeResources=org/pkl/doc/.*") }
tasks.jar { manifest { attributes += mapOf("Main-Class" to "org.pkl.doc.Main") } }
htmlValidator { sources = files("src/test/files/DocGeneratorTest/output") }
tasks.validateHtml { mustRunAfter(testJavaExecutable) }
+1 -4
View File
@@ -69,9 +69,6 @@ class DocCommand : BaseCommand(name = "pkldoc", helpLink = helpLink) {
.single()
.flag(default = false)
private val isTestMode by
option(names = arrayOf("--test-mode"), help = "Internal test mode", hidden = true).flag()
private val projectOptions by ProjectOptions()
override val helpString: String = "Generate HTML documentation from Pkl modules and packages."
@@ -81,7 +78,7 @@ class DocCommand : BaseCommand(name = "pkldoc", helpLink = helpLink) {
CliDocGeneratorOptions(
baseOptions.baseOptions(modules, projectOptions),
outputDir,
isTestMode,
true,
noSymlinks,
)
CliDocGenerator(options).run()
@@ -18,9 +18,11 @@ package org.pkl.doc
import com.google.common.jimfs.Configuration
import com.google.common.jimfs.Jimfs
import java.net.URI
import java.nio.file.FileSystem
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.*
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
@@ -29,20 +31,83 @@ import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import org.pkl.commons.cli.CliBaseOptions
import org.pkl.commons.cli.CliException
import org.pkl.commons.readString
import org.pkl.commons.test.FileTestUtils
import org.pkl.commons.test.PackageServer
import org.pkl.commons.test.listFilesRecursively
import org.pkl.commons.toPath
import org.pkl.commons.walk
import org.pkl.core.Version
import org.pkl.core.util.IoUtils
import org.pkl.doc.DocGenerator.Companion.current
class CliDocGeneratorTest {
companion object {
private val tempFileSystem by lazy { Jimfs.newFileSystem(Configuration.unix()) }
private val tempFileSystem: FileSystem by lazy { Jimfs.newFileSystem(Configuration.unix()) }
private val tmpOutputDir: Path by lazy {
private val tmpOutputDir by lazy {
tempFileSystem.getPath("/work/output").apply { createDirectories() }
}
private val helper = DocGeneratorTestHelper()
private val projectDir = FileTestUtils.rootProjectDir.resolve("pkl-doc")
private val inputDir: Path by lazy {
projectDir.resolve("src/test/files/DocGeneratorTest/input").apply { assert(exists()) }
}
private val docsiteModule: URI by lazy {
inputDir.resolve("docsite-info.pkl").apply { assert(exists()) }.toUri()
}
internal val package1PackageModule: URI by lazy {
inputDir.resolve("com.package1/doc-package-info.pkl").apply { assert(exists()) }.toUri()
}
private val package2PackageModule: URI by lazy {
inputDir.resolve("com.package2/doc-package-info.pkl").apply { assert(exists()) }.toUri()
}
internal val package1InputModules: List<URI> by lazy {
inputDir
.resolve("com.package1")
.listFilesRecursively()
.filter { it.fileName.toString() != "doc-package-info.pkl" }
.map { it.toUri() }
}
private val package2InputModules: List<URI> by lazy {
inputDir
.resolve("com.package2")
.listFilesRecursively()
.filter { it.fileName.toString() != "doc-package-info.pkl" }
.map { it.toUri() }
}
private val expectedOutputDir: Path by lazy {
projectDir.resolve("src/test/files/DocGeneratorTest/output").createDirectories()
}
private val expectedOutputFiles: List<Path> by lazy { expectedOutputDir.listFilesRecursively() }
private val actualOutputDir: Path by lazy { tempFileSystem.getPath("/work/DocGeneratorTest") }
private val actualOutputFiles: List<Path> by lazy { actualOutputDir.listFilesRecursively() }
private val expectedRelativeOutputFiles: List<String> by lazy {
expectedOutputFiles.map { path ->
IoUtils.toNormalizedPathString(expectedOutputDir.relativize(path)).let { str ->
// Git will by default clone symlinks as shortcuts on Windows, and shortcuts have a
// `.lnk` extension.
if (IoUtils.isWindows() && str.endsWith(".lnk")) str.dropLast(4) else str
}
}
}
private val actualRelativeOutputFiles: List<String> by lazy {
actualOutputFiles.map { IoUtils.toNormalizedPathString(actualOutputDir.relativize(it)) }
}
private val binaryFileExtensions = setOf("woff2", "png", "svg")
private fun runDocGenerator(outputDir: Path, cacheDir: Path?, noSymlinks: Boolean = false) {
CliDocGenerator(
@@ -50,14 +115,14 @@ class CliDocGeneratorTest {
CliBaseOptions(
sourceModules =
listOf(
helper.docsiteModule,
helper.package1PackageModule,
helper.package2PackageModule,
docsiteModule,
package1PackageModule,
package2PackageModule,
URI("package://localhost:0/birds@0.5.0"),
URI("package://localhost:0/fruit@1.1.0"),
URI("package://localhost:0/unlisted@1.0.0"),
URI("package://localhost:0/deprecated@1.0.0"),
) + helper.package1InputModules + helper.package2InputModules,
) + package1InputModules + package2InputModules,
moduleCacheDir = cacheDir,
),
outputDir = outputDir,
@@ -70,7 +135,19 @@ class CliDocGeneratorTest {
@JvmStatic
private fun generateDocs(): List<String> {
return helper.generateDocs()
val cacheDir = Files.createTempDirectory("cli-doc-generator-test-cache")
PackageServer.populateCacheDir(cacheDir)
runDocGenerator(actualOutputDir, cacheDir)
val missingFiles = expectedRelativeOutputFiles - actualRelativeOutputFiles.toSet()
if (missingFiles.isNotEmpty()) {
Assertions.fail<Unit>(
"The following expected files were not actually generated:\n" +
missingFiles.joinToString("\n")
)
}
return actualRelativeOutputFiles
}
}
@@ -81,7 +158,6 @@ class CliDocGeneratorTest {
createParentDirectories()
createFile()
}
val descriptor2 =
tempFileSystem.getPath("/work/dir2/docsite-info.pkl").apply {
createParentDirectories()
@@ -144,20 +220,49 @@ class CliDocGeneratorTest {
@ParameterizedTest
@MethodSource("generateDocs")
fun test(relativeFilePath: String) {
DocTestUtils.testExpectedFile(
helper.expectedOutputDir,
helper.actualOutputDir,
relativeFilePath,
)
val actualFile = actualOutputDir.resolve(relativeFilePath)
assertThat(actualFile)
.withFailMessage("Test bug: $actualFile should exist but does not.")
.exists()
// symlinks on Git and Windows is rather finnicky; they create shortcuts by default unless
// a core Git option is set. Also, by default, symlinks require administrator privileges to run.
// We'll just test that the symlink got created but skip verifying that it points to the right
// place.
if (actualFile.isSymbolicLink() && IoUtils.isWindows()) return
val expectedFile = expectedOutputDir.resolve(relativeFilePath)
if (expectedFile.exists()) {
when {
expectedFile.isSymbolicLink() -> {
assertThat(actualFile).isSymbolicLink
assertThat(expectedFile.readSymbolicLink().toString().toPath())
.isEqualTo(actualFile.readSymbolicLink().toString().toPath())
}
expectedFile.extension in binaryFileExtensions ->
assertThat(actualFile.readBytes()).isEqualTo(expectedFile.readBytes())
else -> assertThat(actualFile.readString()).isEqualTo(expectedFile.readString())
}
} else {
expectedFile.createParentDirectories()
if (actualFile.isSymbolicLink()) {
// needs special handling because `copyTo` can't copy symlinks between file systems
val linkTarget = actualFile.readSymbolicLink()
assertThat(linkTarget).isRelative
Files.createSymbolicLink(expectedFile, linkTarget.toString().toPath())
} else {
actualFile.copyTo(expectedFile)
}
Assertions.fail("Created missing expected file `$relativeFilePath`.")
}
}
@Test
fun `creates a symlink called current by default`(@TempDir tempDir: Path) {
PackageServer.populateCacheDir(tempDir)
runDocGenerator(helper.actualOutputDir, tempDir)
runDocGenerator(actualOutputDir, tempDir)
val expectedSymlink = helper.actualOutputDir.resolve("com.package1/current")
val expectedDestination = helper.actualOutputDir.resolve("com.package1/1.2.3")
val expectedSymlink = actualOutputDir.resolve("com.package1/current")
val expectedDestination = actualOutputDir.resolve("com.package1/1.2.3")
assertThat(expectedSymlink).isSymbolicLink().matches {
Files.isSameFile(it, expectedDestination)
@@ -169,10 +274,10 @@ class CliDocGeneratorTest {
@TempDir tempDir: Path
) {
PackageServer.populateCacheDir(tempDir)
runDocGenerator(helper.actualOutputDir, tempDir, noSymlinks = true)
runDocGenerator(actualOutputDir, tempDir, noSymlinks = true)
val currentDirectory = helper.actualOutputDir.resolve("com.package1/current")
val sourceDirectory = helper.actualOutputDir.resolve("com.package1/1.2.3")
val currentDirectory = actualOutputDir.resolve("com.package1/current")
val sourceDirectory = actualOutputDir.resolve("com.package1/1.2.3")
assertThat(currentDirectory).isDirectory()
assertThat(currentDirectory.isSymbolicLink()).isFalse()
@@ -1,181 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.net.URI
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.createDirectories
import kotlin.io.path.exists
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.fail
import org.pkl.commons.cli.CliBaseOptions
import org.pkl.commons.test.FileTestUtils
import org.pkl.commons.test.PackageServer
import org.pkl.commons.test.listFilesRecursively
import org.pkl.core.util.IoUtils
class DocGeneratorTestHelper {
internal val tempDir by lazy { Files.createTempDirectory("ExecutableCliDocGeneratorTest") }
internal val projectDir = FileTestUtils.rootProjectDir.resolve("pkl-doc")
internal val inputDir: Path by lazy {
projectDir.resolve("src/test/files/DocGeneratorTest/input").apply { assert(exists()) }
}
internal val docsiteModule: URI by lazy {
inputDir.resolve("docsite-info.pkl").apply { assert(exists()) }.toUri()
}
internal val package1PackageModule: URI by lazy {
inputDir.resolve("com.package1/doc-package-info.pkl").apply { assert(exists()) }.toUri()
}
internal val package2PackageModule: URI by lazy {
inputDir.resolve("com.package2/doc-package-info.pkl").apply { assert(exists()) }.toUri()
}
internal val package1InputModules: List<URI> by lazy {
inputDir
.resolve("com.package1")
.listFilesRecursively()
.filter { it.fileName.toString() != "doc-package-info.pkl" }
.map { it.toUri() }
}
internal val package2InputModules: List<URI> by lazy {
inputDir
.resolve("com.package2")
.listFilesRecursively()
.filter { it.fileName.toString() != "doc-package-info.pkl" }
.map { it.toUri() }
}
internal val expectedOutputDir: Path by lazy {
projectDir.resolve("src/test/files/DocGeneratorTest/output").createDirectories()
}
internal val expectedOutputFiles: List<Path> by lazy { expectedOutputDir.listFilesRecursively() }
internal val actualOutputDir: Path by lazy {
tempDir.resolve("work/DocGeneratorTest").createDirectories()
}
internal val actualOutputFiles: List<Path> by lazy { actualOutputDir.listFilesRecursively() }
internal val cacheDir: Path by lazy { tempDir.resolve("cache") }
internal val sourceModules =
listOf(
docsiteModule,
package1PackageModule,
package2PackageModule,
URI("package://localhost:0/birds@0.5.0"),
URI("package://localhost:0/fruit@1.1.0"),
URI("package://localhost:0/unlisted@1.0.0"),
URI("package://localhost:0/deprecated@1.0.0"),
) + package1InputModules + package2InputModules
internal val expectedRelativeOutputFiles: List<String> by lazy {
expectedOutputFiles.map { path ->
IoUtils.toNormalizedPathString(expectedOutputDir.relativize(path)).let { str ->
// Git will by default clone symlinks as shortcuts on Windows, and shortcuts have a
// `.lnk` extension.
if (IoUtils.isWindows() && str.endsWith(".lnk")) str.dropLast(4) else str
}
}
}
internal val actualRelativeOutputFiles: List<String> by lazy {
actualOutputFiles.map { IoUtils.toNormalizedPathString(actualOutputDir.relativize(it)) }
}
fun runPklDocCli(executable: Path, options: CliDocGeneratorOptions) {
val command = buildList {
add(executable.toString())
add("--output-dir")
add(options.normalizedOutputDir.toString())
add("--cache-dir")
add(options.base.normalizedModuleCacheDir.toString())
add("--test-mode")
addAll(sourceModules.map { it.toString() })
}
val process =
with(ProcessBuilder(command)) {
redirectErrorStream(true)
start()
}
try {
val out = process.inputStream.reader().readText()
val exitCode = process.waitFor()
if (exitCode != 0) {
fail(
"""
Process exited with $exitCode.
Output:
"""
.trimIndent() + out
)
}
} finally {
process.destroy()
}
}
private fun generateDocsWith(doGenerate: (CliDocGeneratorOptions) -> Unit): List<String> {
PackageServer.populateCacheDir(cacheDir)
val options =
CliDocGeneratorOptions(
CliBaseOptions(
sourceModules =
listOf(
docsiteModule,
package1PackageModule,
package2PackageModule,
URI("package://localhost:0/birds@0.5.0"),
URI("package://localhost:0/fruit@1.1.0"),
URI("package://localhost:0/unlisted@1.0.0"),
URI("package://localhost:0/deprecated@1.0.0"),
) + package1InputModules + package2InputModules,
moduleCacheDir = cacheDir,
),
outputDir = actualOutputDir,
isTestMode = true,
noSymlinks = false,
)
doGenerate(options)
val missingFiles = expectedRelativeOutputFiles - actualRelativeOutputFiles.toSet()
if (missingFiles.isNotEmpty()) {
Assertions.fail<Unit>(
"The following expected files were not actually generated:\n" +
missingFiles.joinToString("\n")
)
}
return actualRelativeOutputFiles
}
fun generateDocsWithCli(executable: Path): List<String> {
return generateDocsWith { runPklDocCli(executable, it) }
}
fun generateDocs(): List<String> {
return generateDocsWith { CliDocGenerator(it).run() }
}
}
@@ -1,73 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.copyTo
import kotlin.io.path.createParentDirectories
import kotlin.io.path.exists
import kotlin.io.path.extension
import kotlin.io.path.isSymbolicLink
import kotlin.io.path.readBytes
import kotlin.io.path.readSymbolicLink
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat
import org.pkl.commons.readString
import org.pkl.commons.toPath
import org.pkl.core.util.IoUtils
object DocTestUtils {
private val binaryFileExtensions = setOf("woff2", "png", "svg")
fun testExpectedFile(expectedOutputDir: Path, actualOutputDir: Path, relativeFilePath: String) {
val actualFile = actualOutputDir.resolve(relativeFilePath)
assertThat(actualFile)
.withFailMessage("Test bug: $actualFile should exist but does not.")
.exists()
// symlinks on Git and Windows is rather finnicky; they create shortcuts by default unless
// a core Git option is set. Also, by default, symlinks require administrator privileges to run.
// We'll just test that the symlink got created but skip verifying that it points to the right
// place.
if (actualFile.isSymbolicLink() && IoUtils.isWindows()) return
val expectedFile = expectedOutputDir.resolve(relativeFilePath)
if (expectedFile.exists()) {
when {
expectedFile.isSymbolicLink() -> {
assertThat(actualFile).isSymbolicLink
assertThat(expectedFile.readSymbolicLink().toString().toPath())
.isEqualTo(actualFile.readSymbolicLink().toString().toPath())
}
expectedFile.extension in binaryFileExtensions ->
assertThat(actualFile.readBytes()).isEqualTo(expectedFile.readBytes())
else -> assertThat(actualFile.readString()).isEqualTo(expectedFile.readString())
}
} else {
expectedFile.createParentDirectories()
if (actualFile.isSymbolicLink()) {
// needs special handling because `copyTo` can't copy symlinks between file systems
val linkTarget = actualFile.readSymbolicLink()
assertThat(linkTarget).isRelative
Files.createSymbolicLink(expectedFile, linkTarget.toString().toPath())
} else {
actualFile.copyTo(expectedFile)
}
Assertions.fail("Created missing expected file `$relativeFilePath`.")
}
}
}
@@ -1,41 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import org.junit.jupiter.api.condition.DisabledIfSystemProperty
import org.junit.jupiter.api.condition.EnabledIfSystemProperty
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import org.pkl.commons.test.Executables
// need both annotations for this to work (see https://stackoverflow.com/a/63252081)
@EnabledIfSystemProperty(named = "org.pkl.doc.JavaExecutableTest", matches = "true")
@DisabledIfSystemProperty(named = "org.pkl.doc.JavaExecutableTest", matches = "(?!true)")
class JavaExecutableTest {
companion object {
val helper = DocGeneratorTestHelper()
@JvmStatic
private fun generateDocs(): List<String> =
helper.generateDocsWithCli(Executables.pkldoc.javaExecutable)
}
@ParameterizedTest()
@MethodSource("generateDocs")
fun test(relativePath: String) {
DocTestUtils.testExpectedFile(helper.expectedOutputDir, helper.actualOutputDir, relativePath)
}
}
@@ -1,42 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import org.junit.jupiter.api.condition.DisabledIfSystemProperty
import org.junit.jupiter.api.condition.EnabledIfSystemProperty
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import org.pkl.commons.test.Executables
// need both annotations for this to work (see https://stackoverflow.com/a/63252081)
@EnabledIfSystemProperty(named = "org.pkl.doc.NativeExecutableTest", matches = "true")
@DisabledIfSystemProperty(named = "org.pkl.doc.NativeExecutableTest", matches = "(?!true)")
class NativeExecutableTest {
companion object {
val helper = DocGeneratorTestHelper()
@JvmStatic
private fun generateDocs(): List<String> {
return helper.generateDocsWithCli(Executables.pkldoc.firstExistingNative)
}
}
@ParameterizedTest()
@MethodSource("generateDocs")
fun test(relativePath: String) {
DocTestUtils.testExpectedFile(helper.expectedOutputDir, helper.actualOutputDir, relativePath)
}
}
@@ -26,17 +26,17 @@ import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Test
import org.pkl.commons.cli.CliBaseOptions
import org.pkl.commons.readString
import org.pkl.doc.CliDocGeneratorTest.Companion.package1InputModules
import org.pkl.doc.CliDocGeneratorTest.Companion.package1PackageModule
class SearchTest {
companion object {
private val tempFileSystem = lazy { Jimfs.newFileSystem(Configuration.unix()) }
private val helper = DocGeneratorTestHelper()
private val jsContext = lazy {
// reuse CliDocGeneratorTest's input files (src/test/files/DocGeneratorTest/input)
val packageModule: URI = helper.package1PackageModule
val inputModules: List<URI> = helper.package1InputModules
val packageModule: URI = package1PackageModule
val inputModules: List<URI> = package1InputModules
val pkldocDir = tempFileSystem.value.rootDirectories.first()
@@ -1,93 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import com.google.common.jimfs.Configuration
import com.google.common.jimfs.Jimfs
import java.net.URI
import java.nio.file.FileSystem
import java.nio.file.Path
import kotlin.io.path.createDirectories
import kotlin.io.path.exists
import org.pkl.commons.test.FileTestUtils
import org.pkl.commons.test.listFilesRecursively
import org.pkl.core.util.IoUtils
class TestUtils {
val tempFileSystem: FileSystem by lazy { Jimfs.newFileSystem(Configuration.unix()) }
val tmpOutputDir by lazy { tempFileSystem.getPath("/work/output").apply { createDirectories() } }
val projectDir = FileTestUtils.rootProjectDir.resolve("pkl-doc")
val inputDir: Path by lazy {
projectDir.resolve("src/test/files/DocGeneratorTest/input").apply { assert(exists()) }
}
val docsiteModule: URI by lazy {
inputDir.resolve("docsite-info.pkl").apply { assert(exists()) }.toUri()
}
internal val package1PackageModule: URI by lazy {
inputDir.resolve("com.package1/doc-package-info.pkl").apply { assert(exists()) }.toUri()
}
val package2PackageModule: URI by lazy {
inputDir.resolve("com.package2/doc-package-info.pkl").apply { assert(exists()) }.toUri()
}
internal val package1InputModules: List<URI> by lazy {
inputDir
.resolve("com.package1")
.listFilesRecursively()
.filter { it.fileName.toString() != "doc-package-info.pkl" }
.map { it.toUri() }
}
val package2InputModules: List<URI> by lazy {
inputDir
.resolve("com.package2")
.listFilesRecursively()
.filter { it.fileName.toString() != "doc-package-info.pkl" }
.map { it.toUri() }
}
val expectedOutputDir: Path by lazy {
projectDir.resolve("src/test/files/DocGeneratorTest/output").createDirectories()
}
val expectedOutputFiles: List<Path> by lazy { expectedOutputDir.listFilesRecursively() }
val actualOutputDir: Path by lazy { tempFileSystem.getPath("/work/DocGeneratorTest") }
val actualOutputFiles: List<Path> by lazy { actualOutputDir.listFilesRecursively() }
val expectedRelativeOutputFiles: List<String> by lazy {
expectedOutputFiles.map { path ->
IoUtils.toNormalizedPathString(expectedOutputDir.relativize(path)).let { str ->
// Git will by default clone symlinks as shortcuts on Windows, and shortcuts have a
// `.lnk` extension.
if (IoUtils.isWindows() && str.endsWith(".lnk")) str.dropLast(4) else str
}
}
}
val actualRelativeOutputFiles: List<String> by lazy {
actualOutputFiles.map { IoUtils.toNormalizedPathString(actualOutputDir.relativize(it)) }
}
val binaryFileExtensions = setOf("woff2", "png", "svg")
}
+8 -8
View File
@@ -3,7 +3,7 @@
# This file is expected to be part of source control.
net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata
org.assertj:assertj-core:3.27.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.polyglot:polyglot:24.1.2=testRuntimeClasspath
org.graalvm.sdk:collections:24.1.2=testRuntimeClasspath
org.graalvm.sdk:graal-sdk:24.1.2=testRuntimeClasspath
@@ -31,13 +31,13 @@ org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21=testCompileClasspath,testImplemen
org.jetbrains.kotlin:kotlin-stdlib:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains:annotations:13.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.4=testRuntimeClasspath
org.junit:junit-bom:5.13.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.3=testRuntimeClasspath
org.junit:junit-bom:5.13.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.msgpack:msgpack-core:0.9.8=testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.organicdesign:Paguro:3.10.3=testRuntimeClasspath
-36
View File
@@ -1,36 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata
org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-build-common:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-build-tools-api:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-build-tools-impl:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-compiler-runner:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-daemon-client:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:2.0.21=kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-native-prebuilt:2.0.21=kotlinNativeBundleConfiguration
org.jetbrains.kotlin:kotlin-reflect:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-script-runtime:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-scripting-common:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-jvm:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.21=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib:2.0.21=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains:annotations:13.0=compileClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.13.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.13.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.13.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.13.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.13.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.13.0=testRuntimeClasspath
org.junit:junit-bom:5.13.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
empty=annotationProcessor,compileOnlyDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDefExtensions,sourcesJar,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDefExtensions
-48
View File
@@ -1,48 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
pklAllProjects
pklKotlinLibrary
pklPublishLibrary
}
dependencies {
api(projects.pklParser)
testImplementation(projects.pklCommonsTest)
}
tasks.test {
inputs
.dir("src/test/files/FormatterSnippetTests/input")
.withPropertyName("formatterSnippetTestsInput")
.withPathSensitivity(PathSensitivity.RELATIVE)
inputs
.dir("src/test/files/FormatterSnippetTests/output")
.withPropertyName("formatterSnippetTestsOutput")
.withPathSensitivity(PathSensitivity.RELATIVE)
}
publishing {
publications {
named<MavenPublication>("library") {
pom {
url.set("https://github.com/apple/pkl/tree/main/pkl-formatter")
description.set("Formatter for Pkl")
}
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,53 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.formatter
import java.nio.file.Files
import java.nio.file.Path
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 {
/**
* Formats a Pkl file from the given file path.
*
* @param path the path to the Pkl file to format
* @return the formatted Pkl source code as a string
* @throws java.io.IOException if the file cannot be read
*/
fun format(path: Path): String {
return format(Files.readString(path))
}
/**
* 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 {
val parser = GenericParser()
val builder = Builder(text)
val gen = Generator()
val ast = parser.parseModule(text)
val formatAst = builder.format(ast)
// force a line at the end of the file
gen.generate(Nodes(listOf(formatAst, ForceLine)))
return gen.toString()
}
}
@@ -1,149 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.formatter
import org.pkl.formatter.ast.Empty
import org.pkl.formatter.ast.ForceLine
import org.pkl.formatter.ast.ForceWrap
import org.pkl.formatter.ast.FormatNode
import org.pkl.formatter.ast.Group
import org.pkl.formatter.ast.IfWrap
import org.pkl.formatter.ast.Indent
import org.pkl.formatter.ast.Line
import org.pkl.formatter.ast.MultilineStringGroup
import org.pkl.formatter.ast.Nodes
import org.pkl.formatter.ast.Space
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()
private var indent: Int = 0
private var size: Int = 0
private val wrapped: MutableSet<Int> = mutableSetOf()
private var shouldAddIndent = false
fun generate(node: FormatNode) {
node(node, Wrap.DETECT)
}
private fun node(node: FormatNode, wrap: Wrap) {
when (node) {
is Empty -> {}
is Nodes -> node.nodes.forEach { node(it, wrap) }
is Group -> {
val width = node.nodes.sumOf { it.width(wrapped) }
val wrap =
if (size + width > MAX) {
wrapped += node.id
Wrap.ENABLED
} else {
Wrap.DETECT
}
node.nodes.forEach { node(it, wrap) }
}
is ForceWrap -> {
wrapped += node.id
val wrap = Wrap.ENABLED
node.nodes.forEach { node(it, wrap) }
}
is IfWrap -> {
if (wrapped.contains(node.id)) {
node(node.ifWrap, Wrap.ENABLED)
} else {
node(node.ifNotWrap, wrap)
}
}
is Text -> text(node.text)
is Line -> {
if (wrap.isEnabled()) {
newline()
}
}
is ForceLine -> newline()
is SpaceOrLine -> {
if (wrap.isEnabled()) {
newline()
} else {
text(" ")
}
}
is Space -> text(" ")
is Indent -> {
if (wrap.isEnabled() && node.nodes.isNotEmpty()) {
size += INDENT.length
indent++
node.nodes.forEach { node(it, wrap) }
indent--
} else {
node.nodes.forEach { node(it, wrap) }
}
}
is MultilineStringGroup -> {
val indentLength = indent * INDENT.length
val offset = (indentLength + 1) - node.endQuoteCol
var previousNewline = false
for ((i, child) in node.nodes.withIndex()) {
when {
child is ForceLine -> newline(shouldIndent = false) // don't indent
child is Text &&
previousNewline &&
child.text.isBlank() &&
child.text.length == indentLength &&
node.nodes[i + 1] is ForceLine -> {}
child is Text && previousNewline && offset != 0 -> text(reposition(child.text, offset))
else -> node(child, Wrap.DETECT) // always detect wrapping
}
previousNewline = child is ForceLine
}
}
}
}
private fun text(value: String) {
if (shouldAddIndent) {
repeat(times = indent) { buf.append(INDENT) }
shouldAddIndent = false
}
size += value.length
buf.append(value)
}
private fun newline(shouldIndent: Boolean = true) {
size = INDENT.length * indent
buf.append('\n')
shouldAddIndent = shouldIndent
}
private fun reposition(text: String, offset: Int): String {
return if (offset > 0) {
" ".repeat(offset) + text
} else {
text.drop(-offset)
}
}
override fun toString(): String {
return buf.toString()
}
companion object {
// max line length
const val MAX = 100
private const val INDENT = " "
}
}
@@ -1,66 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.formatter
internal class NaturalOrderComparator(private val ignoreCase: Boolean = false) :
Comparator<String> {
override fun compare(s1: String, s2: String): Int {
var i = 0
var j = 0
while (i < s1.length && j < s2.length) {
val c1 = if (ignoreCase) s1[i].lowercaseChar() else s1[i]
val c2 = if (ignoreCase) s2[j].lowercaseChar() else s2[j]
if (c1.isDigit() && c2.isDigit()) {
val (num1, nextI) = getNumber(s1, i)
val (num2, nextJ) = getNumber(s2, j)
val numComparison = num1.compareTo(num2)
if (numComparison != 0) {
return numComparison
}
i = nextI
j = nextJ
} else {
val charComparison = c1.compareTo(c2)
if (charComparison != 0) {
return charComparison
}
i++
j++
}
}
return s1.length.compareTo(s2.length)
}
private fun getNumber(s: String, startIndex: Int): LongAndInt {
var i = startIndex
val start = i
while (i < s.length && s[i].isDigit()) {
i++
}
val numStr = s.substring(start, i)
val number = numStr.toLongOrNull() ?: 0L
return LongAndInt(number, i)
}
// use this instead of Pair to avoid boxing
private data class LongAndInt(val l: Long, var i: Int)
}
@@ -1,66 +0,0 @@
/*
* Copyright © 2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.formatter.ast
import org.pkl.formatter.Generator
enum class Wrap {
ENABLED,
DETECT;
fun isEnabled(): Boolean = this == ENABLED
}
sealed interface FormatNode {
fun width(wrapped: Set<Int>): Int =
when (this) {
is Nodes -> nodes.sumOf { it.width(wrapped) }
is Group -> nodes.sumOf { it.width(wrapped) }
is Indent -> nodes.sumOf { it.width(wrapped) }
is ForceWrap -> nodes.sumOf { it.width(wrapped + id) }
is IfWrap -> if (id in wrapped) ifWrap.width(wrapped) else ifNotWrap.width(wrapped)
is Text -> text.length
is SpaceOrLine,
is Space -> 1
is ForceLine,
is MultilineStringGroup -> Generator.MAX
else -> 0
}
}
data class Text(val text: String) : FormatNode
object Empty : FormatNode
object Line : FormatNode
object ForceLine : FormatNode
object SpaceOrLine : FormatNode
object Space : FormatNode
data class Indent(val nodes: List<FormatNode>) : FormatNode
data class Nodes(val nodes: List<FormatNode>) : FormatNode
data class Group(val id: Int, val nodes: List<FormatNode>) : FormatNode
data class ForceWrap(val id: Int, val nodes: List<FormatNode>) : FormatNode
data class MultilineStringGroup(val endQuoteCol: Int, val nodes: List<FormatNode>) : FormatNode
data class IfWrap(val id: Int, val ifWrap: FormatNode, val ifNotWrap: FormatNode) : FormatNode
@@ -1,10 +0,0 @@
class Foo {
}
class Bar
{
qux = 1
}
class Baz { prop = 0; prop2 = 1 }
@@ -1,16 +0,0 @@
function fun(a, b, c, d) = a
noTrailingCommas = fun(1, 2, 3, 4,)
trailingCommas = fun("loooooooooooooooooooongString", "loooooooooooooooongString", "looooooooooooooooongString", "notTooLong")
noTrailingCommaObjParams {
fooooooooooooooooooooooooooooooooo, baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar, baaaaaaaaaaaaaaaaaaaaaz ->
1 + 1
}
trailingCommaInLambdas = (fooooooooooooooooooooooooooooooooo, baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar, baaaaaaaaaaaaaaaaaaaaaz) -> 1
trailingCommaInConstraints: String(isSomethingSomethingSomething, isSomethingElse, isSomethingSomethingSomethingElse)
trailingCommaInTypeParameters: Mapping<SomethingSomethingSomethingSomething, SomethingSomething | SomethingElse>
@@ -1,31 +0,0 @@
module comment.interleaved
local test: Int|String =
if (true)
1 // It's the same as "100%"
else
"8%"
foo: ( // some comment
* String(
// if dtstart is defined and a datetime, until must also be a datetime if defined
true
)
|Int
// trailing comment
)?
foo2: (// some comment
Int, // other comment
String
) ->Int
bar = ( // some comment
10 + 10
// another comment
)
bar2 = ( // some comment
foo, bar
// another comment
) -> foo + bar
@@ -1,8 +0,0 @@
module dangling
/// Doc comment.
///
/// for this field
// sepearted by a stray comment
/// but continues here.
some: String
@@ -1,14 +0,0 @@
//// line 1
///// line 2
foo = 1
/// line 1
///
///
/// line 2
bar = 1
///line 1
///line 2
baz = 1
@@ -1,25 +0,0 @@
foo {
123123123123 + 123123123123 * 123123123123 - 123123123123 / 123123123123 + 123123123123 ** 123123123123
2
3
4
}
bar = clazz.superclass == null || clazz.superclass.reflectee == Module || clazz.superclass.reflectee == Typed
baz =
new Listing {
1
2
} |> mixin1 |> mixin2
qux =
(baz) {
1
2
} {
3
4
}
minus = superLoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongVariable - 100000
@@ -1,5 +0,0 @@
res = myList.map((it) -> it.partition).filter((it) -> someList.contains(it))
res2 = myList.map(lambda1).filter(lambda2)
res3 = myList.map((it) -> it.partition)
@@ -1,7 +0,0 @@
foo =
if (someCondition) 10000
else
if (someOtherCondition) 20000
else
if (someAnotherCondition) 30000
else 4
@@ -1,11 +0,0 @@
foo = let (vaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaariable = 10) 1 * 1
bar = let (someVariable = new Listing {
1
}) 1 * 1
baz =
let (someVariable = 10000000)
let (someOtherVariable = 2000000)
let (someAnotherVariable = 3000000) someVariable + someOtherVariable + someAnotherVariable
@@ -1,19 +0,0 @@
// top level comment
import "@foo/Foo.pkl" as foo
import* "**.pkl"
import "pkl:math"
import "package://example.com/myPackage@1.0.0#/Qux.pkl"
import* "file:///tmp/*.pkl"
import "https://example.com/baz.pkl"
import "module2.pkl"
import "pkl:reflect"
import "..."
import* "@foo/**.pkl"
import "@bar/Bar.pkl"
import "Module12.pkl"
import "module11.pkl"
import "module1.pkl"
@@ -1,51 +0,0 @@
foo = new {
bar = 1
}
class Foo {
baz: Int
}
bar =
new Listing {
1
2
}
baz =
(foo) {
2
3
}
qux =
(x, y) -> new Listing {
x
y
}
forGen = new Listing {
for (someVar in new Listing {
1
2
}) {
[someVar] = someVar
}
}
objParams: Listing<Int> =
new {
default {
key -> key + 1
}
}
objParams2: Listing<Int> = new {
default { someVeryLongParameter1, someVeryLongParameter2, someVeryLongParameter3, someVeryLongParameter4 ->
1
}
}
parenType: (ReaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalyLongType(reaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalylongConstraint))
functionType: (ReaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalyLongType,ReaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalyLongType2) -> String
@@ -1,64 +0,0 @@
module
foo.bar.baz
amends
"bar.pkl"
import
"@foo/Foo.pkl"
as foo
local
open
class Bar {}
const
local
baz = 10
local
function
fun(x) =
x
const local prooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooperty: String = "foo"
local function function2(parameter1: Parameter1Type, parameter2: Parameter2Type, parameter3: Parameter3Type, parameter4: Parameter4Type): String = ""
local const function function3(parameter1: String|Int, parameter2: String|Int): Mapping<String|Int, String> =
new {}
prop = function2(loooooooooooooooooogParameter1, loooooooooooooooooogParameter2, loooooooooooooooooogParameter3, loooooooooooooooooogParameter4)
prop2: String
|Int
|Boolean
funcParam = fun(
(x, y) -> new Listing {
x
y
})
funcParam2 = aFun(foo, 10 * 10, anotherVariable, if (true) 100000 else 200000, (param1, param2) -> param1 * param2)
funcParam3 = aFun(foo, 10 * 10, anotherVariable, 200000, (param1, param2) -> param1 * param2)
funcParam4 = aFun(foo, 10 * 10, anotherVariable, if (true) 100000 else 200000, new Listing {
1
2
})
open local class SomeReallyInterestingClassName<in SomeInParameter, out SomeOutParameter> extends AnotherInterestingClassName {
foo: Int
}
local function resourceMapping(type): Mapping<String, unknown> =
new Mapping { default = (key) -> (type) { metadata { name = key } } }
local const function biiiiiiiiiiiiiiiiiiiiiiiiigFunction(param1: String, param2: String(!isBlank)): Boolean
local const function someFunction(param1: String, param2: String(!isBlank)): Boolean
local function render(currentIndent: String) =
"\(currentIndent)@\(identifier.render(currentIndent))" +
if (body == null) "" else " " + body.render(currentIndent)
@@ -1,20 +0,0 @@
module reaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaly.loooooooooooooooooooooooooooooooog.naaaaaaaaaaaaaaaaaaaaaaaaaame
extends "reaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalyLongModule.pkl"
import "reaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalyLongModule.pkl" as foo
local open class LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongName {}
local open class ReaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalyLongName {}
const hidden loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooogName = 99
const hidden reallyLoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooogName = 99
const local function looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooogName(x: Int, y) = x + y
typealias Foo = LooooooooooooooooooooooooongTypeName|AnotherLooooooooooooooooooooooooongTypeName|OtherLooooooooooooooooooooooooongTypeName
bar: Boolean|Mapping<LooooooooooooooooooooooooooooongTypeName, AnotherLooooooooooooooooooooooooooooongTypeName>(loooooooooooooooooooogConstraint)
hidden foobar: LongType(someVeryyyyyyyloooong, requirements.might.be.even_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooonger)
@@ -1,18 +0,0 @@
module reaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaly.loooooooooooooooooooooooooooooooog.naaaaaaaaaaaaaaaaaaaaaaaaaaaaame
extends "reaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalyLongModule.pkl"
local reallyLongVariableName = true
local anotherReallyLongName = 1
local evenLongerVariableName = 2
/// this property has a reaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaly long doc comment
property = if (reallyLongVariableName) anotherReallyLongName else evenLongerVariableName + anotherReallyLongName
longString = "reaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaly long string"
shortProperty = 1
reaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalyLongVariableName = 10
reaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalyLongVariableName2 =
if (reallyLongVariableName) anotherReallyLongName else evenLongerVariableName + anotherReallyLongName
@@ -1,4 +0,0 @@
foo = Map(1000, "some random string", 20000, "another random string", 30000, "yet another random string")
incorrect = Map("This has", 1000000, "an incorrect number", 2000000, "of parameters", 30000000, "passed to Map")
@@ -1,3 +0,0 @@
hidden const foo = 1
open local class Foo {}
@@ -1,13 +0,0 @@
// comment
// one
/// doc comment
open
module
foo
.bar
amends
"baz.pkl"
@@ -1,29 +0,0 @@
foo = """
asd \(new {
bar = 1
}) asd
"""
bar = """
line 1
line 2
line3
"""
baz = """
\n
\(bar)
line
\u{123}
"""
// remove unneeded spaces
qux = """
foo
bar
baz
\(foo)
"""
@@ -1,22 +0,0 @@
foo: Listing<Int> = new {1 2 3; 4;5 6 7}
bar: Listing<Int> = new { 1 2
3
4
}
lineIsTooBig: Listing<Int> = new { 999999; 1000000; 1000001; 1000002; 1000003; 1000004; 1000005; 1000006; 1000007; 1000008; 1000009 }
lineIsTooBig2 { 999999; 1000000; 1000001; 1000002; 1000003; 1000004; 1000005; 1000006; 1000007; 1000008; 1000009; 1000010 }
baz = new Dynamic {
1 2
3 4
["foo"] = 3; bar = 30
baz = true
}
qux = new Dynamic {1 2 3 prop="prop"; [0]=9}
@@ -1,12 +0,0 @@
/// Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong doc comment
@Annotation { looooooooooooooooooooooooooooooooooooooooooooooooooongVariableName = 10 }
typealias Foo = String
/// Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong doc comment
@Annotation { looooooooooooooooooooooooooooooooooooooooooooooooooongVariableName = 10 }
foo = "should fit in a single line"
/// Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong doc comment
@Annotation { looooooooooooooooooooooooooooooooooooooooooooooooooongVariableName = 10 }
function bar(x): String = "result: \(x)"
@@ -1,23 +0,0 @@
import"foo.pkl"
bar=new Listing < Int > ( !isEmpty ){1;2}//a bar
typealias Typealias=(String,Int)->Boolean
///a baz
///returns its parameter
baz = (x,y,z)->x+y+z
function fun ( x:Int ? ,b :Boolean )= if(b)/***return x**/x else x+bar [0 ]
prop = trace (1) + super . foo + module .foo
prop2 {
for(x in List(1)) {
when(x == 1){
x
}
}
}
choices: "foo" | * "bar" | String

Some files were not shown because too many files have changed in this diff Show More