mirror of
https://github.com/apple/pkl.git
synced 2026-05-25 16:19:20 +02:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d5b6038147 |
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
name: main
|
name: main
|
||||||
title: Main Project
|
title: Main Project
|
||||||
version: 0.29.1
|
version: 0.29.0
|
||||||
prerelease: false
|
prerelease: false
|
||||||
nav:
|
nav:
|
||||||
- nav.adoc
|
- nav.adoc
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// the following attributes must be updated immediately before a release
|
// 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 corresponding to current git commit without -dev suffix or git hash
|
||||||
:pkl-version-no-suffix: 0.29.1
|
:pkl-version-no-suffix: 0.29.0
|
||||||
// tells whether pkl version corresponding to current git commit
|
// tells whether pkl version corresponding to current git commit
|
||||||
// is a release version (:is-release-version: '') or dev version (:!is-release-version:)
|
// is a release version (:is-release-version: '') or dev version (:!is-release-version:)
|
||||||
:is-release-version: ''
|
:is-release-version: ''
|
||||||
@@ -23,9 +23,9 @@ endif::[]
|
|||||||
|
|
||||||
:uri-maven-docsite: https://central.sonatype.com
|
: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[]
|
ifdef::is-release-version[]
|
||||||
:uri-maven-repo: https://repo1.maven.org/maven2
|
:uri-maven-repo: https://repo1.maven.org/maven2
|
||||||
endif::[]
|
endif::[]
|
||||||
@@ -150,5 +150,4 @@ endif::[]
|
|||||||
|
|
||||||
:uri-pkl-roadmap: https://github.com/orgs/apple/projects/12/views/1
|
: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}
|
:uri-sonatype-snapshot-download: https://s01.oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=org.pkl-lang&v={pkl-artifact-version}
|
||||||
|
|||||||
@@ -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
|
:uri-pkl-codegen-java-download: {uri-sonatype-snapshot-download}&a=pkl-cli-codegen-java&e=jar
|
||||||
|
|
||||||
ifdef::is-release-version[]
|
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::[]
|
endif::[]
|
||||||
|
|
||||||
The Java source code generator takes Pkl class definitions as an input, and generates corresponding Java classes with equally named properties.
|
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.
|
It requires Java 17 or higher.
|
||||||
|
|
||||||
ifndef::is-release-version[]
|
ifndef::is-release-version[]
|
||||||
NOTE: Snapshots are published to repository `{uri-snapshot-repo}`.
|
NOTE: Snapshots are published to repository `{uri-sonatype}`.
|
||||||
endif::[]
|
endif::[]
|
||||||
|
|
||||||
==== Gradle
|
==== Gradle
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
include::ROOT:partial$component-attributes.adoc[]
|
include::ROOT:partial$component-attributes.adoc[]
|
||||||
:uri-homebrew: https://brew.sh
|
:uri-homebrew: https://brew.sh
|
||||||
:uri-mise: https://mise.jdx.dev
|
: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-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
|
: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.
|
For instructions, switch to a release version of this page.
|
||||||
endif::[]
|
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]]
|
||||||
=== Download
|
=== Download
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ The `pkl-doc` library is available {uri-pkl-doc-maven}[from Maven Central].
|
|||||||
It requires Java 17 or higher.
|
It requires Java 17 or higher.
|
||||||
|
|
||||||
ifndef::is-release-version[]
|
ifndef::is-release-version[]
|
||||||
NOTE: Snapshots are published to repository `{uri-snapshot-repo}`.
|
NOTE: Snapshots are published to repository `{uri-sonatype}`.
|
||||||
endif::[]
|
endif::[]
|
||||||
|
|
||||||
==== Gradle
|
==== Gradle
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ It requires Java 17 or higher and Gradle 8.1 or higher.
|
|||||||
Earlier Gradle versions are not supported.
|
Earlier Gradle versions are not supported.
|
||||||
|
|
||||||
ifndef::is-release-version[]
|
ifndef::is-release-version[]
|
||||||
NOTE: Snapshots are published to repository `{uri-snapshot-repo}`.
|
NOTE: Snapshots are published to repository `{uri-sonatype}`.
|
||||||
endif::[]
|
endif::[]
|
||||||
|
|
||||||
The plugin is applied as follows:
|
The plugin is applied as follows:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
= Pkl 0.29 Release Notes
|
= Pkl 0.29 Release Notes
|
||||||
:version: 0.29
|
:version: 0.29
|
||||||
:version-minor: 0.29.1
|
:version-minor: 0.29.0
|
||||||
:release-date: July 24th, 2025
|
:release-date: July 24th, 2025
|
||||||
|
|
||||||
include::ROOT:partial$component-attributes.adoc[]
|
include::ROOT:partial$component-attributes.adoc[]
|
||||||
|
|||||||
@@ -1,26 +1,6 @@
|
|||||||
= Changelog
|
= Changelog
|
||||||
include::ROOT:partial$component-attributes.adoc[]
|
include::ROOT:partial$component-attributes.adoc[]
|
||||||
|
|
||||||
[[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]]
|
[[release-0.29.0]]
|
||||||
== 0.29.0 (2025-07-24)
|
== 0.29.0 (2025-07-24)
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
The Pkl team aims to release a new version of Pkl in February, June, and October of each year.
|
The Pkl team aims to release a new version of Pkl in February, June, and October of each year.
|
||||||
|
|
||||||
* xref:0.29.adoc[0.29 Release Notes]
|
|
||||||
* xref:0.28.adoc[0.28 Release Notes]
|
* xref:0.28.adoc[0.28 Release Notes]
|
||||||
* xref:0.27.adoc[0.27 Release Notes]
|
* xref:0.27.adoc[0.27 Release Notes]
|
||||||
* xref:0.26.adoc[0.26 Release Notes]
|
* xref:0.26.adoc[0.26 Release Notes]
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
# suppress inspection "UnusedProperty" for whole file
|
# suppress inspection "UnusedProperty" for whole file
|
||||||
|
|
||||||
group=org.pkl-lang
|
group=org.pkl-lang
|
||||||
version=0.29.1
|
version=0.29.0
|
||||||
|
|
||||||
# google-java-format requires jdk.compiler exports
|
# google-java-format requires jdk.compiler exports
|
||||||
org.gradle.jvmargs= \
|
org.gradle.jvmargs= \
|
||||||
|
|||||||
+3
-3
@@ -2,15 +2,15 @@
|
|||||||
"catalogs": {},
|
"catalogs": {},
|
||||||
"aliases": {
|
"aliases": {
|
||||||
"pkl": {
|
"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": []
|
"java-agents": []
|
||||||
},
|
},
|
||||||
"pkl-codegen-java": {
|
"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": []
|
"java-agents": []
|
||||||
},
|
},
|
||||||
"pkl-codegen-kotlin": {
|
"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": []
|
"java-agents": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.pkl.cli.commands
|
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.default
|
||||||
import com.github.ajalt.clikt.parameters.options.flag
|
import com.github.ajalt.clikt.parameters.options.flag
|
||||||
import com.github.ajalt.clikt.parameters.options.option
|
import com.github.ajalt.clikt.parameters.options.option
|
||||||
@@ -34,7 +33,6 @@ class EvalCommand : ModulesCommand(name = "eval", helpLink = helpLink) {
|
|||||||
names = arrayOf("-o", "--output-path"),
|
names = arrayOf("-o", "--output-path"),
|
||||||
metavar = "path",
|
metavar = "path",
|
||||||
help = "File path where the output file is placed.",
|
help = "File path where the output file is placed.",
|
||||||
completionCandidates = CompletionCandidates.Path,
|
|
||||||
)
|
)
|
||||||
.single()
|
.single()
|
||||||
|
|
||||||
@@ -61,7 +59,6 @@ class EvalCommand : ModulesCommand(name = "eval", helpLink = helpLink) {
|
|||||||
names = arrayOf("-m", "--multiple-file-output-path"),
|
names = arrayOf("-m", "--multiple-file-output-path"),
|
||||||
metavar = "path",
|
metavar = "path",
|
||||||
help = "Directory where a module's multiple file output is placed.",
|
help = "Directory where a module's multiple file output is placed.",
|
||||||
completionCandidates = CompletionCandidates.Path,
|
|
||||||
)
|
)
|
||||||
.single()
|
.single()
|
||||||
.validate {
|
.validate {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.pkl.cli.commands
|
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.Context
|
||||||
import com.github.ajalt.clikt.core.NoOpCliktCommand
|
import com.github.ajalt.clikt.core.NoOpCliktCommand
|
||||||
import com.github.ajalt.clikt.core.subcommands
|
import com.github.ajalt.clikt.core.subcommands
|
||||||
@@ -117,7 +116,6 @@ class PackageCommand : BaseCommand(name = "package", helpLink = helpLink) {
|
|||||||
names = arrayOf("--output-path"),
|
names = arrayOf("--output-path"),
|
||||||
help = "The directory to write artifacts to",
|
help = "The directory to write artifacts to",
|
||||||
metavar = "path",
|
metavar = "path",
|
||||||
completionCandidates = CompletionCandidates.Path,
|
|
||||||
)
|
)
|
||||||
.single()
|
.single()
|
||||||
.default(".out/%{name}@%{version}")
|
.default(".out/%{name}@%{version}")
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.pkl.cli.commands
|
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.argument
|
||||||
import com.github.ajalt.clikt.parameters.arguments.convert
|
import com.github.ajalt.clikt.parameters.arguments.convert
|
||||||
import com.github.ajalt.clikt.parameters.arguments.multiple
|
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)"
|
override val helpString = "Run tests within the given module(s)"
|
||||||
|
|
||||||
val modules: List<URI> by
|
val modules: List<URI> by
|
||||||
argument(
|
argument(name = "modules", help = "Module paths or URIs to evaluate.")
|
||||||
name = "modules",
|
|
||||||
help = "Module paths or URIs to evaluate.",
|
|
||||||
completionCandidates = CompletionCandidates.Path,
|
|
||||||
)
|
|
||||||
.convert { BaseOptions.parseModuleName(it) }
|
.convert { BaseOptions.parseModuleName(it) }
|
||||||
.multiple()
|
.multiple()
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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)
|
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.pkl.commons.cli.commands
|
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.groups.OptionGroup
|
||||||
import com.github.ajalt.clikt.parameters.options.*
|
import com.github.ajalt.clikt.parameters.options.*
|
||||||
import com.github.ajalt.clikt.parameters.types.enum
|
import com.github.ajalt.clikt.parameters.types.enum
|
||||||
@@ -166,7 +165,6 @@ class BaseOptions : OptionGroup() {
|
|||||||
option(
|
option(
|
||||||
names = arrayOf("-f", "--format"),
|
names = arrayOf("-f", "--format"),
|
||||||
help = "Output format to generate. <${output.joinToString()}>",
|
help = "Output format to generate. <${output.joinToString()}>",
|
||||||
completionCandidates = CompletionCandidates.Fixed(output.toSet()),
|
|
||||||
)
|
)
|
||||||
.single()
|
.single()
|
||||||
|
|
||||||
@@ -189,13 +187,9 @@ class BaseOptions : OptionGroup() {
|
|||||||
.splitAll(File.pathSeparator)
|
.splitAll(File.pathSeparator)
|
||||||
|
|
||||||
val settings: URI? by
|
val settings: URI? by
|
||||||
option(
|
option(names = arrayOf("--settings"), help = "Pkl settings module to use.").single().convert {
|
||||||
names = arrayOf("--settings"),
|
parseModuleName(it)
|
||||||
help = "Pkl settings module to use.",
|
}
|
||||||
completionCandidates = CompletionCandidates.Path,
|
|
||||||
)
|
|
||||||
.single()
|
|
||||||
.convert { parseModuleName(it) }
|
|
||||||
|
|
||||||
val timeout: Duration? by
|
val timeout: Duration? by
|
||||||
option(
|
option(
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.pkl.commons.cli.commands
|
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.argument
|
||||||
import com.github.ajalt.clikt.parameters.arguments.convert
|
import com.github.ajalt.clikt.parameters.arguments.convert
|
||||||
import com.github.ajalt.clikt.parameters.arguments.multiple
|
import com.github.ajalt.clikt.parameters.arguments.multiple
|
||||||
@@ -25,11 +24,7 @@ import java.net.URI
|
|||||||
abstract class ModulesCommand(name: String, helpLink: String) :
|
abstract class ModulesCommand(name: String, helpLink: String) :
|
||||||
BaseCommand(name = name, helpLink = helpLink) {
|
BaseCommand(name = name, helpLink = helpLink) {
|
||||||
open val modules: List<URI> by
|
open val modules: List<URI> by
|
||||||
argument(
|
argument(name = "modules", help = "Module paths or URIs to evaluate.")
|
||||||
name = "modules",
|
|
||||||
help = "Module paths or URIs to evaluate.",
|
|
||||||
completionCandidates = CompletionCandidates.Path,
|
|
||||||
)
|
|
||||||
.convert { BaseOptions.parseModuleName(it) }
|
.convert { BaseOptions.parseModuleName(it) }
|
||||||
.multiple(required = true)
|
.multiple(required = true)
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -33,7 +33,7 @@ import org.pkl.parser.syntax.Module;
|
|||||||
@TruffleLanguage.Registration(
|
@TruffleLanguage.Registration(
|
||||||
id = "pkl",
|
id = "pkl",
|
||||||
name = "Pkl",
|
name = "Pkl",
|
||||||
version = "0.29.1",
|
version = "0.29.0",
|
||||||
characterMimeTypes = VmLanguage.MIME_TYPE,
|
characterMimeTypes = VmLanguage.MIME_TYPE,
|
||||||
contextPolicy = ContextPolicy.SHARED)
|
contextPolicy = ContextPolicy.SHARED)
|
||||||
public final class VmLanguage extends TruffleLanguage<VmContext> {
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.CompilerDirectives.TruffleBoundary;
|
||||||
import com.oracle.truffle.api.frame.MaterializedFrame;
|
import com.oracle.truffle.api.frame.MaterializedFrame;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.annotation.concurrent.GuardedBy;
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
import org.graalvm.collections.UnmodifiableEconomicMap;
|
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.CollectionUtils;
|
||||||
import org.pkl.core.util.EconomicMaps;
|
import org.pkl.core.util.EconomicMaps;
|
||||||
import org.pkl.core.util.LateInit;
|
import org.pkl.core.util.LateInit;
|
||||||
import org.pkl.core.util.MutableLong;
|
|
||||||
|
|
||||||
public final class VmMapping extends VmListingOrMapping {
|
public final class VmMapping extends VmListingOrMapping {
|
||||||
private long cachedLength = -1;
|
|
||||||
|
private int cachedEntryCount = -1;
|
||||||
|
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private @LateInit VmSet __allKeys;
|
private @LateInit VmSet __allKeys;
|
||||||
@@ -125,7 +124,7 @@ public final class VmMapping extends VmListingOrMapping {
|
|||||||
// could use shallow force, but deep force is cached
|
// could use shallow force, but deep force is cached
|
||||||
force(false);
|
force(false);
|
||||||
other.force(false);
|
other.force(false);
|
||||||
if (getLength() != other.getLength()) return false;
|
if (getEntryCount() != other.getEntryCount()) return false;
|
||||||
|
|
||||||
var cursor = cachedValues.getEntries();
|
var cursor = cachedValues.getEntries();
|
||||||
while (cursor.advance()) {
|
while (cursor.advance()) {
|
||||||
@@ -163,21 +162,16 @@ public final class VmMapping extends VmListingOrMapping {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@TruffleBoundary
|
// assumes mapping has been forced
|
||||||
public long getLength() {
|
public int getEntryCount() {
|
||||||
if (cachedLength != -1) return cachedLength;
|
if (cachedEntryCount != -1) return cachedEntryCount;
|
||||||
var count = new MutableLong(0);
|
|
||||||
var visited = new HashSet<>();
|
var result = 0;
|
||||||
iterateMembers(
|
for (var key : cachedValues.getKeys()) {
|
||||||
(key, member) -> {
|
if (key instanceof Identifier) continue;
|
||||||
var alreadyVisited = !visited.add(key);
|
result += 1;
|
||||||
// important to record hidden member as visited before skipping it
|
}
|
||||||
// because any overriding member won't carry a `hidden` identifier
|
cachedEntryCount = result;
|
||||||
if (alreadyVisited || member.isLocalOrExternalOrHidden()) return true;
|
return result;
|
||||||
count.getAndIncrement();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
cachedLength = count.get();
|
|
||||||
return cachedLength;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.pkl.core.stdlib.base;
|
|||||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
import com.oracle.truffle.api.nodes.IndirectCallNode;
|
import com.oracle.truffle.api.nodes.IndirectCallNode;
|
||||||
|
import java.util.HashSet;
|
||||||
import org.pkl.core.ast.lambda.ApplyVmFunction1Node;
|
import org.pkl.core.ast.lambda.ApplyVmFunction1Node;
|
||||||
import org.pkl.core.ast.lambda.ApplyVmFunction2Node;
|
import org.pkl.core.ast.lambda.ApplyVmFunction2Node;
|
||||||
import org.pkl.core.ast.lambda.ApplyVmFunction2NodeGen;
|
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.stdlib.ExternalPropertyNode;
|
||||||
import org.pkl.core.util.EconomicMaps;
|
import org.pkl.core.util.EconomicMaps;
|
||||||
import org.pkl.core.util.MutableBoolean;
|
import org.pkl.core.util.MutableBoolean;
|
||||||
|
import org.pkl.core.util.MutableLong;
|
||||||
import org.pkl.core.util.MutableReference;
|
import org.pkl.core.util.MutableReference;
|
||||||
|
|
||||||
public final class MappingNodes {
|
public final class MappingNodes {
|
||||||
@@ -51,8 +53,20 @@ public final class MappingNodes {
|
|||||||
|
|
||||||
public abstract static class length extends ExternalPropertyNode {
|
public abstract static class length extends ExternalPropertyNode {
|
||||||
@Specialization
|
@Specialization
|
||||||
|
@TruffleBoundary
|
||||||
protected long eval(VmMapping self) {
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.IoUtils;
|
||||||
import org.pkl.core.util.Nullable;
|
import org.pkl.core.util.Nullable;
|
||||||
|
|
||||||
/**
|
// https://yaml.org/spec/1.2.2/#57-escaped-characters
|
||||||
* 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>
|
|
||||||
*/
|
|
||||||
public final class YamlEscaper extends AbstractCharEscaper {
|
public final class YamlEscaper extends AbstractCharEscaper {
|
||||||
private static final String[] REPLACEMENTS;
|
private static final String[] REPLACEMENTS;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
REPLACEMENTS = new String[0xA0 + 1];
|
REPLACEMENTS = new String[0x22 + 1];
|
||||||
for (var i = 0; i < 0x20; i++) {
|
for (var i = 0; i < 0x20; i++) {
|
||||||
REPLACEMENTS[i] = IoUtils.toHexEscape(i);
|
REPLACEMENTS[i] = IoUtils.toHexEscape(i);
|
||||||
}
|
}
|
||||||
// ns-esc-null
|
|
||||||
REPLACEMENTS[0x00] = "\\0";
|
REPLACEMENTS[0x00] = "\\0";
|
||||||
// ns-esc-bell
|
|
||||||
REPLACEMENTS[0x07] = "\\a";
|
REPLACEMENTS[0x07] = "\\a";
|
||||||
// ns-esc-backspace
|
|
||||||
REPLACEMENTS[0x08] = "\\b";
|
REPLACEMENTS[0x08] = "\\b";
|
||||||
// ns-esc-horizontal-tab
|
|
||||||
REPLACEMENTS[0x09] = "\\t";
|
REPLACEMENTS[0x09] = "\\t";
|
||||||
// ns-esc-line-feed
|
|
||||||
REPLACEMENTS[0x0A] = "\\n";
|
REPLACEMENTS[0x0A] = "\\n";
|
||||||
// ns-esc-vertical-tab
|
|
||||||
REPLACEMENTS[0x0B] = "\\v";
|
REPLACEMENTS[0x0B] = "\\v";
|
||||||
// ns-esc-form-feed
|
|
||||||
REPLACEMENTS[0x0C] = "\\f";
|
REPLACEMENTS[0x0C] = "\\f";
|
||||||
// ns-esc-carriage-return
|
|
||||||
REPLACEMENTS[0x0D] = "\\r";
|
REPLACEMENTS[0x0D] = "\\r";
|
||||||
// ns-esc-escape
|
|
||||||
REPLACEMENTS[0x1B] = "\\e";
|
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] = "\\\"";
|
REPLACEMENTS[0x22] = "\\\"";
|
||||||
// ns-esc-backslash
|
|
||||||
REPLACEMENTS[0x5c] = "\\\\";
|
|
||||||
// ns-esc-next-line
|
|
||||||
REPLACEMENTS[0x85] = "\\N";
|
|
||||||
// ns-esc-non-breaking-space
|
|
||||||
REPLACEMENTS[0xA0] = "\\_";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected @Nullable String findReplacement(char ch) {
|
protected @Nullable String findReplacement(char ch) {
|
||||||
//noinspection UnnecessaryUnicodeEscape
|
//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 {}
|
|
||||||
}
|
|
||||||
+2
-2
@@ -114,12 +114,12 @@ examples {
|
|||||||
render(".NAN")
|
render(".NAN")
|
||||||
render(".nAn") // never float
|
render(".nAn") // never float
|
||||||
}
|
}
|
||||||
|
|
||||||
["tag like strings"] {
|
["tag like strings"] {
|
||||||
"!!bool true"
|
"!!bool true"
|
||||||
"!!str my string value"
|
"!!str my string value"
|
||||||
}
|
}
|
||||||
|
|
||||||
["number like string keys"] {
|
["number like string keys"] {
|
||||||
render(new Dynamic {
|
render(new Dynamic {
|
||||||
`0` = "0"
|
`0` = "0"
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
`
|
|
||||||
@@ -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)
|
|
||||||
@@ -27,10 +27,10 @@ import org.junit.platform.engine.EngineDiscoveryRequest
|
|||||||
import org.junit.platform.engine.TestDescriptor
|
import org.junit.platform.engine.TestDescriptor
|
||||||
import org.junit.platform.engine.UniqueId
|
import org.junit.platform.engine.UniqueId
|
||||||
import org.junit.platform.engine.support.descriptor.EngineDescriptor
|
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.FileTestUtils
|
||||||
import org.pkl.commons.test.InputOutputTestEngine
|
import org.pkl.commons.test.InputOutputTestEngine
|
||||||
import org.pkl.commons.test.PackageServer
|
import org.pkl.commons.test.PackageServer
|
||||||
|
import org.pkl.commons.test.PklExecutablePaths
|
||||||
import org.pkl.core.http.HttpClient
|
import org.pkl.core.http.HttpClient
|
||||||
import org.pkl.core.project.Project
|
import org.pkl.core.project.Project
|
||||||
import org.pkl.core.util.IoUtils
|
import org.pkl.core.util.IoUtils
|
||||||
@@ -298,27 +298,27 @@ abstract class AbstractNativeLanguageSnippetTestsEngine : AbstractLanguageSnippe
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MacAmd64LanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
|
class MacAmd64LanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
|
||||||
override val pklExecutablePath: Path = Executables.pkl.macAmd64
|
override val pklExecutablePath: Path = PklExecutablePaths.macAmd64
|
||||||
override val testClass: KClass<*> = MacLanguageSnippetTests::class
|
override val testClass: KClass<*> = MacLanguageSnippetTests::class
|
||||||
}
|
}
|
||||||
|
|
||||||
class MacAarch64LanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
|
class MacAarch64LanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
|
||||||
override val pklExecutablePath: Path = Executables.pkl.macAarch64
|
override val pklExecutablePath: Path = PklExecutablePaths.macAarch64
|
||||||
override val testClass: KClass<*> = MacLanguageSnippetTests::class
|
override val testClass: KClass<*> = MacLanguageSnippetTests::class
|
||||||
}
|
}
|
||||||
|
|
||||||
class LinuxAmd64LanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
|
class LinuxAmd64LanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
|
||||||
override val pklExecutablePath: Path = Executables.pkl.linuxAmd64
|
override val pklExecutablePath: Path = PklExecutablePaths.linuxAmd64
|
||||||
override val testClass: KClass<*> = LinuxLanguageSnippetTests::class
|
override val testClass: KClass<*> = LinuxLanguageSnippetTests::class
|
||||||
}
|
}
|
||||||
|
|
||||||
class LinuxAarch64LanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
|
class LinuxAarch64LanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
|
||||||
override val pklExecutablePath: Path = Executables.pkl.linuxAarch64
|
override val pklExecutablePath: Path = PklExecutablePaths.linuxAarch64
|
||||||
override val testClass: KClass<*> = LinuxLanguageSnippetTests::class
|
override val testClass: KClass<*> = LinuxLanguageSnippetTests::class
|
||||||
}
|
}
|
||||||
|
|
||||||
class AlpineLanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
|
class AlpineLanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
|
||||||
override val pklExecutablePath: Path = Executables.pkl.alpineAmd64
|
override val pklExecutablePath: Path = PklExecutablePaths.alpineAmd64
|
||||||
override val testClass: KClass<*> = AlpineLanguageSnippetTests::class
|
override val testClass: KClass<*> = AlpineLanguageSnippetTests::class
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +340,7 @@ private val windowsNativeExcludedTests
|
|||||||
)
|
)
|
||||||
|
|
||||||
class WindowsLanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
|
class WindowsLanguageSnippetTestsEngine : AbstractNativeLanguageSnippetTestsEngine() {
|
||||||
override val pklExecutablePath: Path = Executables.pkl.windowsAmd64
|
override val pklExecutablePath: Path = PklExecutablePaths.windowsAmd64
|
||||||
override val testClass: KClass<*> = WindowsLanguageSnippetTests::class
|
override val testClass: KClass<*> = WindowsLanguageSnippetTests::class
|
||||||
override val excludedTests: List<Regex>
|
override val excludedTests: List<Regex>
|
||||||
get() = super.excludedTests + windowsNativeExcludedTests + windowsExcludedTests
|
get() = super.excludedTests + windowsNativeExcludedTests + windowsExcludedTests
|
||||||
|
|||||||
@@ -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") } }
|
tasks.jar { manifest { attributes += mapOf("Main-Class" to "org.pkl.doc.Main") } }
|
||||||
|
|
||||||
htmlValidator { sources = files("src/test/files/DocGeneratorTest/output") }
|
htmlValidator { sources = files("src/test/files/DocGeneratorTest/output") }
|
||||||
|
|
||||||
tasks.validateHtml { mustRunAfter(testJavaExecutable) }
|
|
||||||
|
|||||||
@@ -69,9 +69,6 @@ class DocCommand : BaseCommand(name = "pkldoc", helpLink = helpLink) {
|
|||||||
.single()
|
.single()
|
||||||
.flag(default = false)
|
.flag(default = false)
|
||||||
|
|
||||||
private val isTestMode by
|
|
||||||
option(names = arrayOf("--test-mode"), help = "Internal test mode", hidden = true).flag()
|
|
||||||
|
|
||||||
private val projectOptions by ProjectOptions()
|
private val projectOptions by ProjectOptions()
|
||||||
|
|
||||||
override val helpString: String = "Generate HTML documentation from Pkl modules and packages."
|
override val helpString: String = "Generate HTML documentation from Pkl modules and packages."
|
||||||
@@ -81,7 +78,7 @@ class DocCommand : BaseCommand(name = "pkldoc", helpLink = helpLink) {
|
|||||||
CliDocGeneratorOptions(
|
CliDocGeneratorOptions(
|
||||||
baseOptions.baseOptions(modules, projectOptions),
|
baseOptions.baseOptions(modules, projectOptions),
|
||||||
outputDir,
|
outputDir,
|
||||||
isTestMode,
|
true,
|
||||||
noSymlinks,
|
noSymlinks,
|
||||||
)
|
)
|
||||||
CliDocGenerator(options).run()
|
CliDocGenerator(options).run()
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ package org.pkl.doc
|
|||||||
import com.google.common.jimfs.Configuration
|
import com.google.common.jimfs.Configuration
|
||||||
import com.google.common.jimfs.Jimfs
|
import com.google.common.jimfs.Jimfs
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
import java.nio.file.FileSystem
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.*
|
import kotlin.io.path.*
|
||||||
|
import org.assertj.core.api.Assertions
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.assertThrows
|
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.junit.jupiter.params.provider.MethodSource
|
||||||
import org.pkl.commons.cli.CliBaseOptions
|
import org.pkl.commons.cli.CliBaseOptions
|
||||||
import org.pkl.commons.cli.CliException
|
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.PackageServer
|
||||||
|
import org.pkl.commons.test.listFilesRecursively
|
||||||
|
import org.pkl.commons.toPath
|
||||||
import org.pkl.commons.walk
|
import org.pkl.commons.walk
|
||||||
import org.pkl.core.Version
|
import org.pkl.core.Version
|
||||||
|
import org.pkl.core.util.IoUtils
|
||||||
import org.pkl.doc.DocGenerator.Companion.current
|
import org.pkl.doc.DocGenerator.Companion.current
|
||||||
|
|
||||||
class CliDocGeneratorTest {
|
class CliDocGeneratorTest {
|
||||||
companion object {
|
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() }
|
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) {
|
private fun runDocGenerator(outputDir: Path, cacheDir: Path?, noSymlinks: Boolean = false) {
|
||||||
CliDocGenerator(
|
CliDocGenerator(
|
||||||
@@ -50,14 +115,14 @@ class CliDocGeneratorTest {
|
|||||||
CliBaseOptions(
|
CliBaseOptions(
|
||||||
sourceModules =
|
sourceModules =
|
||||||
listOf(
|
listOf(
|
||||||
helper.docsiteModule,
|
docsiteModule,
|
||||||
helper.package1PackageModule,
|
package1PackageModule,
|
||||||
helper.package2PackageModule,
|
package2PackageModule,
|
||||||
URI("package://localhost:0/birds@0.5.0"),
|
URI("package://localhost:0/birds@0.5.0"),
|
||||||
URI("package://localhost:0/fruit@1.1.0"),
|
URI("package://localhost:0/fruit@1.1.0"),
|
||||||
URI("package://localhost:0/unlisted@1.0.0"),
|
URI("package://localhost:0/unlisted@1.0.0"),
|
||||||
URI("package://localhost:0/deprecated@1.0.0"),
|
URI("package://localhost:0/deprecated@1.0.0"),
|
||||||
) + helper.package1InputModules + helper.package2InputModules,
|
) + package1InputModules + package2InputModules,
|
||||||
moduleCacheDir = cacheDir,
|
moduleCacheDir = cacheDir,
|
||||||
),
|
),
|
||||||
outputDir = outputDir,
|
outputDir = outputDir,
|
||||||
@@ -70,7 +135,19 @@ class CliDocGeneratorTest {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private fun generateDocs(): List<String> {
|
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()
|
createParentDirectories()
|
||||||
createFile()
|
createFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
val descriptor2 =
|
val descriptor2 =
|
||||||
tempFileSystem.getPath("/work/dir2/docsite-info.pkl").apply {
|
tempFileSystem.getPath("/work/dir2/docsite-info.pkl").apply {
|
||||||
createParentDirectories()
|
createParentDirectories()
|
||||||
@@ -144,20 +220,49 @@ class CliDocGeneratorTest {
|
|||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("generateDocs")
|
@MethodSource("generateDocs")
|
||||||
fun test(relativeFilePath: String) {
|
fun test(relativeFilePath: String) {
|
||||||
DocTestUtils.testExpectedFile(
|
val actualFile = actualOutputDir.resolve(relativeFilePath)
|
||||||
helper.expectedOutputDir,
|
assertThat(actualFile)
|
||||||
helper.actualOutputDir,
|
.withFailMessage("Test bug: $actualFile should exist but does not.")
|
||||||
relativeFilePath,
|
.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
|
@Test
|
||||||
fun `creates a symlink called current by default`(@TempDir tempDir: Path) {
|
fun `creates a symlink called current by default`(@TempDir tempDir: Path) {
|
||||||
PackageServer.populateCacheDir(tempDir)
|
PackageServer.populateCacheDir(tempDir)
|
||||||
runDocGenerator(helper.actualOutputDir, tempDir)
|
runDocGenerator(actualOutputDir, tempDir)
|
||||||
|
|
||||||
val expectedSymlink = helper.actualOutputDir.resolve("com.package1/current")
|
val expectedSymlink = actualOutputDir.resolve("com.package1/current")
|
||||||
val expectedDestination = helper.actualOutputDir.resolve("com.package1/1.2.3")
|
val expectedDestination = actualOutputDir.resolve("com.package1/1.2.3")
|
||||||
|
|
||||||
assertThat(expectedSymlink).isSymbolicLink().matches {
|
assertThat(expectedSymlink).isSymbolicLink().matches {
|
||||||
Files.isSameFile(it, expectedDestination)
|
Files.isSameFile(it, expectedDestination)
|
||||||
@@ -169,10 +274,10 @@ class CliDocGeneratorTest {
|
|||||||
@TempDir tempDir: Path
|
@TempDir tempDir: Path
|
||||||
) {
|
) {
|
||||||
PackageServer.populateCacheDir(tempDir)
|
PackageServer.populateCacheDir(tempDir)
|
||||||
runDocGenerator(helper.actualOutputDir, tempDir, noSymlinks = true)
|
runDocGenerator(actualOutputDir, tempDir, noSymlinks = true)
|
||||||
|
|
||||||
val currentDirectory = helper.actualOutputDir.resolve("com.package1/current")
|
val currentDirectory = actualOutputDir.resolve("com.package1/current")
|
||||||
val sourceDirectory = helper.actualOutputDir.resolve("com.package1/1.2.3")
|
val sourceDirectory = actualOutputDir.resolve("com.package1/1.2.3")
|
||||||
|
|
||||||
assertThat(currentDirectory).isDirectory()
|
assertThat(currentDirectory).isDirectory()
|
||||||
assertThat(currentDirectory.isSymbolicLink()).isFalse()
|
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.junit.jupiter.api.Test
|
||||||
import org.pkl.commons.cli.CliBaseOptions
|
import org.pkl.commons.cli.CliBaseOptions
|
||||||
import org.pkl.commons.readString
|
import org.pkl.commons.readString
|
||||||
|
import org.pkl.doc.CliDocGeneratorTest.Companion.package1InputModules
|
||||||
|
import org.pkl.doc.CliDocGeneratorTest.Companion.package1PackageModule
|
||||||
|
|
||||||
class SearchTest {
|
class SearchTest {
|
||||||
companion object {
|
companion object {
|
||||||
private val tempFileSystem = lazy { Jimfs.newFileSystem(Configuration.unix()) }
|
private val tempFileSystem = lazy { Jimfs.newFileSystem(Configuration.unix()) }
|
||||||
|
|
||||||
private val helper = DocGeneratorTestHelper()
|
|
||||||
|
|
||||||
private val jsContext = lazy {
|
private val jsContext = lazy {
|
||||||
// reuse CliDocGeneratorTest's input files (src/test/files/DocGeneratorTest/input)
|
// reuse CliDocGeneratorTest's input files (src/test/files/DocGeneratorTest/input)
|
||||||
val packageModule: URI = helper.package1PackageModule
|
val packageModule: URI = package1PackageModule
|
||||||
val inputModules: List<URI> = helper.package1InputModules
|
val inputModules: List<URI> = package1InputModules
|
||||||
|
|
||||||
val pkldocDir = tempFileSystem.value.rootDirectories.first()
|
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")
|
|
||||||
}
|
|
||||||
@@ -489,7 +489,7 @@ public class Lexer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void lexQuotedIdentifier() {
|
private void lexQuotedIdentifier() {
|
||||||
while (lookahead != '`' && lookahead != '\n' && lookahead != '\r' && lookahead != EOF) {
|
while (lookahead != '`' && lookahead != '\n' && lookahead != '\r') {
|
||||||
nextChar();
|
nextChar();
|
||||||
}
|
}
|
||||||
if (lookahead == '`') {
|
if (lookahead == '`') {
|
||||||
@@ -705,13 +705,6 @@ public class Lexer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ParserError unexpectedChar(char got, String didYouMean) {
|
private ParserError unexpectedChar(char got, String didYouMean) {
|
||||||
if (got == EOF) {
|
|
||||||
return unexpectedChar("EOF", didYouMean);
|
|
||||||
}
|
|
||||||
return lexError("unexpectedCharacter", got, didYouMean);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ParserError unexpectedChar(String got, String didYouMean) {
|
|
||||||
return lexError("unexpectedCharacter", got, didYouMean);
|
return lexError("unexpectedCharacter", got, didYouMean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package org.pkl.parser
|
|||||||
|
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.assertThrows
|
|
||||||
|
|
||||||
class LexerTest {
|
class LexerTest {
|
||||||
|
|
||||||
@@ -47,10 +46,4 @@ class LexerTest {
|
|||||||
assertThat(Lexer.maybeQuoteIdentifier("this")).isEqualTo("`this`")
|
assertThat(Lexer.maybeQuoteIdentifier("this")).isEqualTo("`this`")
|
||||||
assertThat(Lexer.maybeQuoteIdentifier("😀")).isEqualTo("`😀`")
|
assertThat(Lexer.maybeQuoteIdentifier("😀")).isEqualTo("`😀`")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun lexSingleBacktick() {
|
|
||||||
val thrown = assertThrows<ParserError> { Lexer("`").next() }
|
|
||||||
assertThat(thrown).hasMessageContaining("Unexpected character `EOF`")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ internal class BinaryEvaluator(
|
|||||||
override fun visitMapping(value: VmMapping) {
|
override fun visitMapping(value: VmMapping) {
|
||||||
packer.packArrayHeader(2)
|
packer.packArrayHeader(2)
|
||||||
packer.packInt(CODE_MAPPING.toInt())
|
packer.packInt(CODE_MAPPING.toInt())
|
||||||
packer.packMapHeader(value.length.toInt())
|
packer.packMapHeader(value.entryCount)
|
||||||
value.iterateAlreadyForcedMemberValues { key, _, memberValue ->
|
value.iterateAlreadyForcedMemberValues { key, _, memberValue ->
|
||||||
visit(key)
|
visit(key)
|
||||||
visit(memberValue)
|
visit(memberValue)
|
||||||
|
|||||||
@@ -13,9 +13,3 @@ res4: Mapping = new {
|
|||||||
["bar"] = 2
|
["bar"] = 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// https://github.com/apple/pkl/issues/1151
|
|
||||||
res5: Mapping = new {
|
|
||||||
local self = this
|
|
||||||
["foo"] = new Dynamic { name = "foo" }
|
|
||||||
["bar"] = new Dynamic { name = self["foo"].name + "bar" }
|
|
||||||
}
|
|
||||||
|
|||||||
+1
-25
@@ -41,28 +41,4 @@
|
|||||||
:
|
:
|
||||||
- 3
|
- 3
|
||||||
-
|
-
|
||||||
bar: 2
|
bar: 2
|
||||||
-
|
|
||||||
- 16
|
|
||||||
- res5
|
|
||||||
-
|
|
||||||
- 3
|
|
||||||
-
|
|
||||||
foo:
|
|
||||||
- 1
|
|
||||||
- Dynamic
|
|
||||||
- pkl:base
|
|
||||||
-
|
|
||||||
-
|
|
||||||
- 16
|
|
||||||
- name
|
|
||||||
- foo
|
|
||||||
bar:
|
|
||||||
- 1
|
|
||||||
- Dynamic
|
|
||||||
- pkl:base
|
|
||||||
-
|
|
||||||
-
|
|
||||||
- 16
|
|
||||||
- name
|
|
||||||
- foobar
|
|
||||||
@@ -17,7 +17,7 @@ package org.pkl.server
|
|||||||
|
|
||||||
import org.junit.jupiter.api.AfterEach
|
import org.junit.jupiter.api.AfterEach
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.pkl.commons.test.Executables
|
import org.pkl.commons.test.PklExecutablePaths
|
||||||
import org.pkl.core.messaging.MessageTransports
|
import org.pkl.core.messaging.MessageTransports
|
||||||
|
|
||||||
class NativeServerTest : AbstractServerTest() {
|
class NativeServerTest : AbstractServerTest() {
|
||||||
@@ -26,7 +26,7 @@ class NativeServerTest : AbstractServerTest() {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun beforeEach() {
|
fun beforeEach() {
|
||||||
val executable = Executables.pkl.firstExistingNative.toString()
|
val executable = PklExecutablePaths.firstExisting.toString()
|
||||||
server = ProcessBuilder(executable, "server").start()
|
server = ProcessBuilder(executable, "server").start()
|
||||||
client =
|
client =
|
||||||
TestTransport(
|
TestTransport(
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
///
|
///
|
||||||
/// Warning: Although this module is ready for initial use,
|
/// Warning: Although this module is ready for initial use,
|
||||||
/// benchmark results may be inaccurate or inconsistent.
|
/// benchmark results may be inaccurate or inconsistent.
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.Benchmark
|
module pkl.Benchmark
|
||||||
|
|
||||||
import "pkl:platform" as _platform
|
import "pkl:platform" as _platform
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
/// @Deprecated { message = "Use `com.example.Birds.Parrot` instead" }
|
/// @Deprecated { message = "Use `com.example.Birds.Parrot` instead" }
|
||||||
/// amends "pkl:PackageInfo"
|
/// amends "pkl:PackageInfo"
|
||||||
/// ```
|
/// ```
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.DocPackageInfo
|
module pkl.DocPackageInfo
|
||||||
|
|
||||||
import "pkl:reflect"
|
import "pkl:reflect"
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
///
|
///
|
||||||
/// title = "Title displayed in the header of each page"
|
/// title = "Title displayed in the header of each page"
|
||||||
/// ```
|
/// ```
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.DocsiteInfo
|
module pkl.DocsiteInfo
|
||||||
|
|
||||||
import "pkl:reflect"
|
import "pkl:reflect"
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Common settings for Pkl's own evaluator.
|
/// Common settings for Pkl's own evaluator.
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
@Since { version = "0.26.0" }
|
@Since { version = "0.26.0" }
|
||||||
module pkl.EvaluatorSettings
|
module pkl.EvaluatorSettings
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -64,7 +64,7 @@
|
|||||||
/// value = project
|
/// value = project
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.Project
|
module pkl.Project
|
||||||
|
|
||||||
import "pkl:EvaluatorSettings" as EvaluatorSettingsModule
|
import "pkl:EvaluatorSettings" as EvaluatorSettingsModule
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@
|
|||||||
/// These tools differentiate from [pkl:reflect][reflect] in that they parse Pkl modules, but do not
|
/// These tools differentiate from [pkl:reflect][reflect] in that they parse Pkl modules, but do not
|
||||||
/// execute any code within these modules.
|
/// execute any code within these modules.
|
||||||
@Since { version = "0.27.0" }
|
@Since { version = "0.27.0" }
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.analyze
|
module pkl.analyze
|
||||||
|
|
||||||
// used by doc comments
|
// used by doc comments
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@
|
|||||||
/// Fundamental properties, methods, and classes for writing Pkl programs.
|
/// Fundamental properties, methods, and classes for writing Pkl programs.
|
||||||
///
|
///
|
||||||
/// Members of this module are automatically available in every Pkl module.
|
/// Members of this module are automatically available in every Pkl module.
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.base
|
module pkl.base
|
||||||
|
|
||||||
import "pkl:jsonnet"
|
import "pkl:jsonnet"
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// A JSON parser.
|
/// A JSON parser.
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.json
|
module pkl.json
|
||||||
|
|
||||||
/// A JSON parser.
|
/// A JSON parser.
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// A [Jsonnet](https://jsonnet.org) renderer.
|
/// A [Jsonnet](https://jsonnet.org) renderer.
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.jsonnet
|
module pkl.jsonnet
|
||||||
|
|
||||||
/// Constructs an [ImportStr].
|
/// Constructs an [ImportStr].
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@
|
|||||||
///
|
///
|
||||||
/// Note that some mathematical functions, such as `sign()`, `abs()`, and `round()`,
|
/// Note that some mathematical functions, such as `sign()`, `abs()`, and `round()`,
|
||||||
/// are directly defined in classes [Number], [Int], and [Float].
|
/// are directly defined in classes [Number], [Int], and [Float].
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.math
|
module pkl.math
|
||||||
|
|
||||||
/// The minimum [Int] value: `-9223372036854775808`.
|
/// The minimum [Int] value: `-9223372036854775808`.
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Information about the platform that the current program runs on.
|
/// Information about the platform that the current program runs on.
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.platform
|
module pkl.platform
|
||||||
|
|
||||||
/// The platform that the current program runs on.
|
/// The platform that the current program runs on.
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
/// A renderer for [Protocol Buffers](https://developers.google.com/protocol-buffers).
|
/// A renderer for [Protocol Buffers](https://developers.google.com/protocol-buffers).
|
||||||
/// Note: This module is _experimental_ and not ready for production use.
|
/// Note: This module is _experimental_ and not ready for production use.
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.protobuf
|
module pkl.protobuf
|
||||||
|
|
||||||
import "pkl:reflect"
|
import "pkl:reflect"
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@
|
|||||||
/// - Documentation generators (such as *Pkldoc*)
|
/// - Documentation generators (such as *Pkldoc*)
|
||||||
/// - Code generators (such as *pkl-codegen-java* and *pkl-codegen-kotlin*)
|
/// - Code generators (such as *pkl-codegen-java* and *pkl-codegen-kotlin*)
|
||||||
/// - Domain-specific schema validators
|
/// - Domain-specific schema validators
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.reflect
|
module pkl.reflect
|
||||||
|
|
||||||
import "pkl:base"
|
import "pkl:base"
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Information about the Pkl release that the current program runs on.
|
/// Information about the Pkl release that the current program runs on.
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.release
|
module pkl.release
|
||||||
|
|
||||||
import "pkl:semver"
|
import "pkl:semver"
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Parsing, comparison, and manipulation of [semantic version](https://semver.org/spec/v2.0.0.html) numbers.
|
/// Parsing, comparison, and manipulation of [semantic version](https://semver.org/spec/v2.0.0.html) numbers.
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.semver
|
module pkl.semver
|
||||||
|
|
||||||
/// Tells whether [version] is a valid semantic version number.
|
/// Tells whether [version] is a valid semantic version number.
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@
|
|||||||
/// Every settings file must amend this module.
|
/// Every settings file must amend this module.
|
||||||
/// Unless CLI commands and build tool plugins are explicitly configured with a settings file,
|
/// Unless CLI commands and build tool plugins are explicitly configured with a settings file,
|
||||||
/// they will use `~/.pkl/settings.pkl` or the defaults specified in this module.
|
/// they will use `~/.pkl/settings.pkl` or the defaults specified in this module.
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.settings
|
module pkl.settings
|
||||||
|
|
||||||
import "pkl:EvaluatorSettings"
|
import "pkl:EvaluatorSettings"
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// Utilities for generating shell scripts.
|
/// Utilities for generating shell scripts.
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.shell
|
module pkl.shell
|
||||||
|
|
||||||
/// Escapes [str] by enclosing it in single quotes.
|
/// Escapes [str] by enclosing it in single quotes.
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@
|
|||||||
///
|
///
|
||||||
/// To write tests, amend this module and define [facts] or [examples] (or both).
|
/// To write tests, amend this module and define [facts] or [examples] (or both).
|
||||||
/// To run tests, evaluate the amended module.
|
/// To run tests, evaluate the amended module.
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
open module pkl.test
|
open module pkl.test
|
||||||
|
|
||||||
/// Named groups of boolean expressions that are expected to evaluate to [true].
|
/// Named groups of boolean expressions that are expected to evaluate to [true].
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// An XML renderer.
|
/// An XML renderer.
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.xml
|
module pkl.xml
|
||||||
|
|
||||||
/// Renders values as XML.
|
/// Renders values as XML.
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// A YAML 1.2 compliant YAML parser.
|
/// A YAML 1.2 compliant YAML parser.
|
||||||
@ModuleInfo { minPklVersion = "0.29.1" }
|
@ModuleInfo { minPklVersion = "0.29.0" }
|
||||||
module pkl.yaml
|
module pkl.yaml
|
||||||
|
|
||||||
/// A YAML parser.
|
/// A YAML parser.
|
||||||
|
|||||||
Reference in New Issue
Block a user