Compare commits

..

No commits in common. "main" and "0.2.3" have entirely different histories.
main ... 0.2.3

129 changed files with 776 additions and 2225 deletions

View File

@ -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.
@ -13,9 +13,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// ===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
amends "package://pkg.pkl-lang.org/pkl-project-commons/pkl.impl.circleci@1.1.1#/PklCI.pkl" amends "package://pkg.pkl-lang.org/pkl-project-commons/pkl.impl.circleci@1.0.1#/PklCI.pkl"
import "pkl:semver"
local swiftTest = new RunStep { local swiftTest = new RunStep {
name = "swift test" name = "swift test"
@ -25,78 +23,59 @@ local swiftTest = new RunStep {
""" """
} }
local class PklDistribution { local pklVersion = "0.25.1"
/// The version of this distribution local pklBinary = "https://repo1.maven.org/maven2/org/pkl-lang/pkl-cli-linux-amd64/\(pklVersion)/pkl-cli-linux-amd64-\(pklVersion).bin"
version: String(semver.isValid(this))
/// Normalized version for use in task names local downloadPkl = new RunStep {
fixed normalizedVersion: String = version.replaceAll(".", "-") name = "Downloading pkl"
command = """
/// The URL to download this distribution mkdir /tmp/pkl
fixed downloadUrl: String = "https://github.com/apple/pkl/releases/download/\(version)/pkl-linux-amd64" curl -L "\(pklBinary)" > /tmp/pkl/pkl
chmod +x /tmp/pkl/pkl
fixed downloadRunStep: RunStep = new { echo 'export PKL_EXEC=/tmp/pkl/pkl' >> $BASH_ENV
name = "Downloading pkl-\(version)" """
command = """
PKL=$(mktemp /tmp/pkl-\(version)-XXXXXX)
curl -L "\(downloadUrl)" > $PKL
chmod +x $PKL
echo "export PKL_EXEC=$PKL" >> $BASH_ENV
"""
}
} }
local pklCurrent: PklDistribution = new {
version = "0.27.2"
}
local pklDistributions: Listing<PklDistribution> = new {
new { version = "0.25.3" }
pklCurrent
}
local testJobs = jobs.keys.filter((it) -> it.startsWith("test"))
main { main {
jobs { jobs {
...testJobs "test"
} }
} }
prb { prb {
jobs { jobs {
...testJobs "test"
} }
} }
release { release {
jobs { jobs {
...testJobs "test"
new { new {
["pkl-package"] { ["pkl-package"] {
requires { requires {
...testJobs "test"
} }
} }
} }
new { new {
["pkl-gen-swift-macos"] { ["pkl-gen-swift-macos"] {
requires { requires {
...testJobs "test"
} }
} }
} }
new { new {
["pkl-gen-swift-linux-amd64"] { ["pkl-gen-swift-linux-amd64"] {
requires { requires {
...testJobs "test"
} }
} }
} }
new { new {
["pkl-gen-swift-linux-aarch64"] { ["pkl-gen-swift-linux-aarch64"] {
requires { requires {
...testJobs "test"
} }
} }
} }
@ -121,53 +100,22 @@ triggerDocsBuild = "release"
triggerPackageDocsBuild = "release" triggerPackageDocsBuild = "release"
jobs { jobs {
for (distribution in pklDistributions) { ["test"] {
["test-pkl-\(distribution.normalizedVersion)"] {
docker {
new {
image = "swift:5.9-rhel-ubi9"
}
}
resource_class = "xlarge"
steps {
"checkout"
distribution.downloadRunStep
swiftTest
new RunStep { command = "make circleci-config" }
new RunStep { command = "make test-snippets" }
new RunStep { command = "make test-pkl" }
new RunStep { command = "make generate-fixtures" }
new StoreTestResults {
path = ".out/test-results/"
}
}
}
}
["test-license-headers"] {
docker {
new {
image = "ghcr.io/korandoru/hawkeye"
}
}
steps {
"checkout"
new RunStep {
command = "/bin/hawkeye check --fail-if-unknown"
}
}
}
["test-format"] {
docker { docker {
new { new {
image = "swift:5.9-rhel-ubi9" image = "swift:5.9-rhel-ubi9"
} }
} }
resource_class = "xlarge"
steps { steps {
"checkout" "checkout"
new RunStep { downloadPkl
command = "make swiftformat-lint" swiftTest
new RunStep { command = "make test-snippets" }
new RunStep { command = "make test-pkl" }
new RunStep { command = "make generate-fixtures" }
new StoreTestResults {
path = ".out/test-results/"
} }
} }
} }
@ -220,7 +168,7 @@ jobs {
} }
steps { steps {
"checkout" "checkout"
pklCurrent.downloadRunStep downloadPkl
new RunStep { new RunStep {
// TODO remove skip-publish-check after initial release // TODO remove skip-publish-check after initial release
command = #"$PKL_EXEC project package --skip-publish-check --output-path out/pkl-package/ codegen/src/"# command = #"$PKL_EXEC project package --skip-publish-check --output-path out/pkl-package/ codegen/src/"#
@ -268,7 +216,7 @@ jobs {
--title "${CIRCLE_TAG}" \ --title "${CIRCLE_TAG}" \
--target "${CIRCLE_SHA1}" \ --target "${CIRCLE_SHA1}" \
--verify-tag \ --verify-tag \
--notes "Release notes: https://pkl-lang.org/swift/current/CHANGELOG.html#release-${CIRCLE_TAG}" \ --notes "Release notes: https://pkl-lang.org/swift/CHANGELOG.html#release-${CIRCLE_TAG}" \
--repo "${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" \ --repo "${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" \
out/pkl-gen-swift/* out/pkl-gen-swift/*
"""# """#

View File

@ -3,23 +3,21 @@ version: '2.1'
orbs: orbs:
pr-approval: apple/pr-approval@0.1.0 pr-approval: apple/pr-approval@0.1.0
jobs: jobs:
test-pkl-0-25-3: test:
steps: steps:
- checkout - checkout
- run: - run:
command: |- command: |-
PKL=$(mktemp /tmp/pkl-0.25.3-XXXXXX) mkdir /tmp/pkl
curl -L "https://github.com/apple/pkl/releases/download/0.25.3/pkl-linux-amd64" > $PKL curl -L "https://repo1.maven.org/maven2/org/pkl-lang/pkl-cli-linux-amd64/0.25.1/pkl-cli-linux-amd64-0.25.1.bin" > /tmp/pkl/pkl
chmod +x $PKL chmod +x /tmp/pkl/pkl
echo "export PKL_EXEC=$PKL" >> $BASH_ENV echo 'export PKL_EXEC=/tmp/pkl/pkl' >> $BASH_ENV
name: Downloading pkl-0.25.3 name: Downloading pkl
- run: - run:
command: |- command: |-
mkdir -p .out/test-results/ mkdir -p .out/test-results/
swift test -vv --parallel --num-workers 1 --xunit-output .out/test-results/xunit.xml -Xswiftc -warnings-as-errors swift test -vv --parallel --num-workers 1 --xunit-output .out/test-results/xunit.xml -Xswiftc -warnings-as-errors
name: swift test name: swift test
- run:
command: make circleci-config
- run: - run:
command: make test-snippets command: make test-snippets
- run: - run:
@ -31,48 +29,6 @@ jobs:
resource_class: xlarge resource_class: xlarge
docker: docker:
- image: swift:5.9-rhel-ubi9 - image: swift:5.9-rhel-ubi9
test-pkl-0-27-2:
steps:
- checkout
- run:
command: |-
PKL=$(mktemp /tmp/pkl-0.27.2-XXXXXX)
curl -L "https://github.com/apple/pkl/releases/download/0.27.2/pkl-linux-amd64" > $PKL
chmod +x $PKL
echo "export PKL_EXEC=$PKL" >> $BASH_ENV
name: Downloading pkl-0.27.2
- run:
command: |-
mkdir -p .out/test-results/
swift test -vv --parallel --num-workers 1 --xunit-output .out/test-results/xunit.xml -Xswiftc -warnings-as-errors
name: swift test
- run:
command: make circleci-config
- run:
command: make test-snippets
- run:
command: make test-pkl
- run:
command: make generate-fixtures
- store_test_results:
path: .out/test-results/
resource_class: xlarge
docker:
- image: swift:5.9-rhel-ubi9
test-license-headers:
steps:
- checkout
- run:
command: /bin/hawkeye check --fail-if-unknown
docker:
- image: ghcr.io/korandoru/hawkeye
test-format:
steps:
- checkout
- run:
command: make swiftformat-lint
docker:
- image: swift:5.9-rhel-ubi9
pkl-gen-swift-macos: pkl-gen-swift-macos:
steps: steps:
- checkout - checkout
@ -126,11 +82,11 @@ jobs:
- checkout - checkout
- run: - run:
command: |- command: |-
PKL=$(mktemp /tmp/pkl-0.27.2-XXXXXX) mkdir /tmp/pkl
curl -L "https://github.com/apple/pkl/releases/download/0.27.2/pkl-linux-amd64" > $PKL curl -L "https://repo1.maven.org/maven2/org/pkl-lang/pkl-cli-linux-amd64/0.25.1/pkl-cli-linux-amd64-0.25.1.bin" > /tmp/pkl/pkl
chmod +x $PKL chmod +x /tmp/pkl/pkl
echo "export PKL_EXEC=$PKL" >> $BASH_ENV echo 'export PKL_EXEC=/tmp/pkl/pkl' >> $BASH_ENV
name: Downloading pkl-0.27.2 name: Downloading pkl
- run: - run:
command: $PKL_EXEC project package --skip-publish-check --output-path out/pkl-package/ codegen/src/ command: $PKL_EXEC project package --skip-publish-check --output-path out/pkl-package/ codegen/src/
- persist_to_workspace: - persist_to_workspace:
@ -169,7 +125,7 @@ jobs:
--title "${CIRCLE_TAG}" \ --title "${CIRCLE_TAG}" \
--target "${CIRCLE_SHA1}" \ --target "${CIRCLE_SHA1}" \
--verify-tag \ --verify-tag \
--notes "Release notes: https://pkl-lang.org/swift/current/CHANGELOG.html#release-${CIRCLE_TAG}" \ --notes "Release notes: https://pkl-lang.org/swift/CHANGELOG.html#release-${CIRCLE_TAG}" \
--repo "${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" \ --repo "${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" \
out/pkl-gen-swift/* out/pkl-gen-swift/*
name: Do release name: Do release
@ -208,53 +164,24 @@ workflows:
type: approval type: approval
- pr-approval/authenticate: - pr-approval/authenticate:
context: pkl-pr-approval context: pkl-pr-approval
- test-pkl-0-25-3: - test:
requires:
- hold
- test-pkl-0-27-2:
requires:
- hold
- test-license-headers:
requires:
- hold
- test-format:
requires: requires:
- hold - hold
- pr-approval/authenticate
when: when:
matches: matches:
value: << pipeline.git.branch >> value: << pipeline.git.branch >>
pattern: ^pull/\d+(/head)?$ pattern: ^pull/\d+(/head)?$
main: main:
jobs: jobs:
- test-pkl-0-25-3 - test
- test-pkl-0-27-2
- test-license-headers
- test-format
when: when:
equal: equal:
- main - main
- << pipeline.git.branch >> - << pipeline.git.branch >>
release: release:
jobs: jobs:
- test-pkl-0-25-3: - test:
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- test-pkl-0-27-2:
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- test-license-headers:
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- test-format:
filters: filters:
branches: branches:
ignore: /.*/ ignore: /.*/
@ -262,10 +189,7 @@ workflows:
only: /^v?\d+\.\d+\.\d+$/ only: /^v?\d+\.\d+\.\d+$/
- pkl-package: - pkl-package:
requires: requires:
- test-pkl-0-25-3 - test
- test-pkl-0-27-2
- test-license-headers
- test-format
filters: filters:
branches: branches:
ignore: /.*/ ignore: /.*/
@ -273,10 +197,7 @@ workflows:
only: /^v?\d+\.\d+\.\d+$/ only: /^v?\d+\.\d+\.\d+$/
- pkl-gen-swift-macos: - pkl-gen-swift-macos:
requires: requires:
- test-pkl-0-25-3 - test
- test-pkl-0-27-2
- test-license-headers
- test-format
filters: filters:
branches: branches:
ignore: /.*/ ignore: /.*/
@ -284,10 +205,7 @@ workflows:
only: /^v?\d+\.\d+\.\d+$/ only: /^v?\d+\.\d+\.\d+$/
- pkl-gen-swift-linux-amd64: - pkl-gen-swift-linux-amd64:
requires: requires:
- test-pkl-0-25-3 - test
- test-pkl-0-27-2
- test-license-headers
- test-format
filters: filters:
branches: branches:
ignore: /.*/ ignore: /.*/
@ -295,10 +213,7 @@ workflows:
only: /^v?\d+\.\d+\.\d+$/ only: /^v?\d+\.\d+\.\d+$/
- pkl-gen-swift-linux-aarch64: - pkl-gen-swift-linux-aarch64:
requires: requires:
- test-pkl-0-25-3 - test
- test-pkl-0-27-2
- test-license-headers
- test-format
filters: filters:
branches: branches:
ignore: /.*/ ignore: /.*/

4
.gitignore vendored
View File

@ -1,6 +1,5 @@
.DS_Store .DS_Store
.build .build
.index-build
/Packages /Packages
/*.xcodeproj /*.xcodeproj
xcuserdata/ xcuserdata/
@ -17,5 +16,4 @@ DerivedData/
.out/ .out/
out/ out/
.cicd/ .cicd/
.pkl-lsp/

View File

@ -1,4 +0,0 @@
version: 1
builder:
configs:
- documentation_targets: ['PklSwift']

View File

@ -15,8 +15,9 @@
--guardelse same-line --guardelse same-line
--nevertrailing filter --nevertrailing filter
--extensionacl on-declarations --extensionacl on-declarations
--header "// ===----------------------------------------------------------------------===//\n// Copyright © {year} Apple Inc. and the Pkl project authors. All rights reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// https://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ===----------------------------------------------------------------------===//"
# rules # rules
--disable spaceAroundOperators --disable spaceAroundOperators
--disable wrapMultilineStatementBraces --disable wrapMultilineStatementBraces

View File

@ -1,31 +0,0 @@
= Development
== Running the formatter
This project uses two formatting tools: https://github.com/korandoru/hawkeye[hawkeye] and https://github.com/nicklockwood/SwiftFormat[SwiftFormat].
To install swiftformat:
[source,shell]
----
brew install swiftformat
----
To install hawkeye locally, you will need to install the https://rustup.rs[Rust toolchain], then run:
[source,shell]
----
cargo install hawkeye
----
To run formatters:
[source,shell]
----
make format
# Alternatively, individually:
swiftformat .
hawkeye format
----

View File

@ -108,19 +108,3 @@ pkl-gen-swift-release: $(PKL_GEN_SWIFT_RELEASE)
.PHONY: pkl-gen-swift-release-output .PHONY: pkl-gen-swift-release-output
pkl-gen-swift-release-output: pkl-gen-swift-release-output:
@echo "$(PKL_GEN_SWIFT_RELEASE)" | xargs @echo "$(PKL_GEN_SWIFT_RELEASE)" | xargs
.PHONY: circleci-config
circleci-config:
$(PKL_EXEC) eval .circleci/config.pkl -o .circleci/config.yml
git diff --exit-code
swiftformat:
swift package plugin --allow-writing-to-package-directory swiftformat .
swiftformat-lint:
swift package plugin --allow-writing-to-package-directory swiftformat --lint .
license-format: .build/tools/hawkeye
.build/tools/hawkeye format
format: swiftformat license-format

View File

@ -1,14 +1,5 @@
{ {
"pins" : [ "pins" : [
{
"identity" : "semanticversion",
"kind" : "remoteSourceControl",
"location" : "https://github.com/SwiftPackageIndex/SemanticVersion",
"state" : {
"revision" : "ea8eea9d89842a29af1b8e6c7677f1c86e72fa42",
"version" : "0.4.0"
}
},
{ {
"identity" : "swift-argument-parser", "identity" : "swift-argument-parser",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
@ -18,24 +9,6 @@
"version" : "1.2.3" "version" : "1.2.3"
} }
}, },
{
"identity" : "swift-docc-plugin",
"kind" : "remoteSourceControl",
"location" : "https://github.com/swiftlang/swift-docc-plugin",
"state" : {
"revision" : "85e4bb4e1cd62cec64a4b8e769dcefdf0c5b9d64",
"version" : "1.4.3"
}
},
{
"identity" : "swift-docc-symbolkit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/swiftlang/swift-docc-symbolkit",
"state" : {
"revision" : "b45d1f2ed151d057b54504d653e0da5552844e34",
"version" : "1.0.0"
}
},
{ {
"identity" : "swift-system", "identity" : "swift-system",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
@ -44,15 +17,6 @@
"revision" : "025bcb1165deab2e20d4eaba79967ce73013f496", "revision" : "025bcb1165deab2e20d4eaba79967ce73013f496",
"version" : "1.2.1" "version" : "1.2.1"
} }
},
{
"identity" : "swiftformat",
"kind" : "remoteSourceControl",
"location" : "https://github.com/nicklockwood/SwiftFormat",
"state" : {
"revision" : "468a7d32dedc8d352c191594b3b45d9fd8ba291b",
"version" : "0.55.5"
}
} }
], ],
"version" : 2 "version" : 2

View File

@ -1,20 +1,4 @@
// swift-tools-version: 5.9 // swift-tools-version: 5.9
//===----------------------------------------------------------------------===//
// 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.
//===----------------------------------------------------------------------===//
import PackageDescription import PackageDescription
let package = Package( let package = Package(
@ -22,6 +6,7 @@ let package = Package(
platforms: [ platforms: [
// required because of `Duration` API // required because of `Duration` API
.macOS(.v13), .macOS(.v13),
.iOS(.v13),
], ],
products: [ products: [
.library( .library(
@ -40,16 +25,11 @@ let package = Package(
dependencies: [ dependencies: [
.package(url: "https://github.com/apple/swift-system", from: "1.2.1"), .package(url: "https://github.com/apple/swift-system", from: "1.2.1"),
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.2.3"), .package(url: "https://github.com/apple/swift-argument-parser", from: "1.2.3"),
.package(url: "https://github.com/SwiftPackageIndex/SemanticVersion", from: "0.4.0"),
// to enable `swift package generate-documentation --target PklSwift`
.package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.1.0"),
// to enable `swift package plugin --allow-writing-to-package-directory swiftformat`
.package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.55.0"),
], ],
targets: [ targets: [
.target( .target(
name: "PklSwift", name: "PklSwift",
dependencies: ["MessagePack", "PklSwiftInternals", "SemanticVersion"] dependencies: ["MessagePack", "PklSwiftInternals"]
), ),
.target( .target(
name: "PklSwiftInternals" name: "PklSwiftInternals"
@ -68,10 +48,6 @@ let package = Package(
], ],
resources: [.embedInCode("Resources/VERSION.txt")] resources: [.embedInCode("Resources/VERSION.txt")]
), ),
.executableTarget(
name: "test-external-reader",
dependencies: ["PklSwift"]
),
.testTarget( .testTarget(
name: "PklSwiftTests", name: "PklSwiftTests",
dependencies: [ dependencies: [

View File

@ -8,4 +8,4 @@ The full documentation for this library can be found on our link:https://pkl-lan
To get up and going, reference the link:https://pkl-lang.org/swift/current/quickstart.html[quick start guide]. To get up and going, reference the link:https://pkl-lang.org/swift/current/quickstart.html[quick start guide].
When upgrading pkl-swift, reference the link:https://pkl-lang.org/swift/current/CHANGELOG.html[changelog] for details. When upgrading pkl-swift, reference the link:https://pkl-lang.org/pkl/swift/current/CHANGELOG.html[changelog] for details.

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
struct AnyCodingKey: CodingKey, Equatable { struct AnyCodingKey: CodingKey, Equatable {
let stringValue: String let stringValue: String

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
@ -185,6 +185,7 @@ extension MessagePackValue {
case .ext: case .ext:
// TODO: implement this? // TODO: implement this?
fatalError("Cannot convert \(self) to \(T.self)") fatalError("Cannot convert \(self) to \(T.self)")
case .timestamp: case .timestamp:
// TODO: implement this? // TODO: implement this?
fatalError("Cannot convert \(self) to \(T.self)") fatalError("Cannot convert \(self) to \(T.self)")

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation

View File

@ -1,22 +1,22 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
#if os(Linux) || os(Windows) #if os(Linux)
let NSEC_PER_SEC: UInt64 = 1_000_000_000 let NSEC_PER_SEC: UInt64 = 1_000_000_000
#endif #endif

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
@ -44,13 +44,10 @@ public final class MessagePackEncoder {
try Box<Data>(data).encode(to: encoder) try Box<Data>(data).encode(to: encoder)
case let date as Date: case let date as Date:
try Box<Date>(date).encode(to: encoder) try Box<Date>(date).encode(to: encoder)
case let bytes as [UInt8]:
try Box<[UInt8]>(bytes).encode(to: encoder)
case let url as URL: case let url as URL:
try Box<URL>(url).encode(to: encoder) try Box<URL>(url).encode(to: encoder)
case let bytes as [UInt8]:
guard type(of: value) == [UInt8].self else {
fallthrough
}
try Box<[UInt8]>(bytes).encode(to: encoder)
default: default:
try value.encode(to: encoder) try value.encode(to: encoder)
} }

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
@ -304,6 +304,8 @@ extension _MessagePackEncoder.SingleValueContainer: SingleValueEncodingContainer
try self.encode(data) try self.encode(data)
case let date as Date: case let date as Date:
try self.encode(date) try self.encode(date)
case let bytes as [UInt8]:
try self.encode(bytes)
case let url as URL: case let url as URL:
try self.encode(url) try self.encode(url)
case let bool as Bool: case let bool as Bool:
@ -332,16 +334,9 @@ extension _MessagePackEncoder.SingleValueContainer: SingleValueEncodingContainer
try self.encode(uint64) try self.encode(uint64)
case let num as any BinaryInteger & Encodable: case let num as any BinaryInteger & Encodable:
try self.encode(num) try self.encode(num)
case let bytes as [UInt8]:
guard type(of: value) == [UInt8].self else {
fallthrough
}
try self.encode(bytes)
default: default:
let writer: Writer = BufferWriter() let writer: Writer = BufferWriter()
let encoder = _MessagePackEncoder() let encoder = _MessagePackEncoder()
encoder.userInfo = userInfo
encoder.codingPath = codingPath
try value.encode(to: encoder) try value.encode(to: encoder)
try encoder.write(into: writer) try encoder.write(into: writer)
let data = (writer as! BufferWriter).bytes let data = (writer as! BufferWriter).bytes

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
extension FixedWidthInteger { extension FixedWidthInteger {
init(bytes: [UInt8]) { init(bytes: [UInt8]) {

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
public protocol Writer { public protocol Writer {
/// Write the given bytes into an output somewhere. /// Write the given bytes into an output somewhere.

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
import MessagePack import MessagePack

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation

View File

@ -0,0 +1,45 @@
// ===----------------------------------------------------------------------===//
// 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.
// ===----------------------------------------------------------------------===//
import Foundation
/// Pair is the Swift representation of Pkl's `pkl.Pair`.
public struct Pair<A, B>: Hashable where A: Hashable, B: Hashable {
public init(_ first: A, _ second: B) {
self.first = first
self.second = second
}
/// The value of the first component of this ``Pair``.
let first: A
/// The value of the second component of this ``Pair``.
let second: B
}
extension Pair: CustomStringConvertible where A: CustomStringConvertible, B: CustomStringConvertible {
public var description: String {
"Pair(\(self.first.description), \(self.second.description))"
}
}
extension Pair: Decodable where A: Decodable, B: Decodable {
public init(from decoder: Decoder) throws {
var partsDecoder = try decoder.unkeyedContainer()
self.first = try partsDecoder.decode(A.self)
self.second = try partsDecoder.decode(B.self)
}
}

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
import MessagePack import MessagePack
@ -205,7 +205,6 @@ extension _PklDecoder {
)) ))
} }
var arr: [AnyHashable?] = [] var arr: [AnyHashable?] = []
arr.reserveCapacity(pklArray.count)
for v in pklArray { for v in pklArray {
try arr.append(self.decodePolymorphic(v, codingPath: codingPath)?.value) try arr.append(self.decodePolymorphic(v, codingPath: codingPath)?.value)
} }

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import MessagePack import MessagePack

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import MessagePack import MessagePack
@ -37,13 +37,11 @@ class PklSingleValueDecodingContainer: SingleValueDecodingContainer {
switch self.value { switch self.value {
case .bool(let value): return value case .bool(let value): return value
default: default:
throw DecodingError.typeMismatch( throw DecodingError.dataCorrupted(
Bool.self,
.init( .init(
codingPath: self.codingPath, codingPath: self.codingPath,
debugDescription: "Expected a boolean, but got \(self.value.debugDataTypeDescription)" debugDescription: "Expected a boolean, but got \(self.value.debugDataTypeDescription)"
) ))
)
} }
} }
@ -51,13 +49,11 @@ class PklSingleValueDecodingContainer: SingleValueDecodingContainer {
switch self.value { switch self.value {
case .string(let value): return value case .string(let value): return value
default: default:
throw DecodingError.typeMismatch( throw DecodingError.dataCorrupted(
String.self,
.init( .init(
codingPath: self.codingPath, codingPath: self.codingPath,
debugDescription: "Expected a string, but got \(self.value.debugDataTypeDescription)" debugDescription: "Expected a string, but got \(self.value.debugDataTypeDescription)"
) ))
)
} }
} }
@ -65,13 +61,11 @@ class PklSingleValueDecodingContainer: SingleValueDecodingContainer {
switch self.value { switch self.value {
case .float(let value): return Double(value) case .float(let value): return Double(value)
default: default:
throw DecodingError.typeMismatch( throw DecodingError.dataCorrupted(
Double.self,
.init( .init(
codingPath: self.codingPath, codingPath: self.codingPath,
debugDescription: "Expected a float, but got \(self.value.debugDataTypeDescription)" debugDescription: "Expected a float, but got \(self.value.debugDataTypeDescription)"
) ))
)
} }
} }
@ -79,13 +73,11 @@ class PklSingleValueDecodingContainer: SingleValueDecodingContainer {
switch self.value { switch self.value {
case .float(let value): return Float(value) case .float(let value): return Float(value)
default: default:
throw DecodingError.typeMismatch( throw DecodingError.dataCorrupted(
Float.self,
.init( .init(
codingPath: self.codingPath, codingPath: self.codingPath,
debugDescription: "Expected a float, but got \(self.value.debugDataTypeDescription)" debugDescription: "Expected a float, but got \(self.value.debugDataTypeDescription)"
) ))
)
} }
} }
@ -132,7 +124,7 @@ class PklSingleValueDecodingContainer: SingleValueDecodingContainer {
func decode<T>(_ type: T.Type) throws -> T where T: Decodable { func decode<T>(_ type: T.Type) throws -> T where T: Decodable {
if type == PklAny.self { if type == PklAny.self {
guard let result = try _PklDecoder.decodePolymorphic(value, codingPath: codingPath) else { guard let result = try _PklDecoder.decodePolymorphic(value, codingPath: codingPath) else {
throw DecodingError.typeMismatch(T.self, .init(codingPath: self.codingPath, debugDescription: "Tried to decode but got nil")) throw DecodingError.dataCorrupted(.init(codingPath: self.codingPath, debugDescription: "Tried to decode but got nil"))
} }
return result as! T return result as! T
} }
@ -143,25 +135,13 @@ class PklSingleValueDecodingContainer: SingleValueDecodingContainer {
private func decodeBinaryInteger<T>() throws -> T where T: BinaryInteger { private func decodeBinaryInteger<T>() throws -> T where T: BinaryInteger {
switch self.value { switch self.value {
case .int(let value): case .int(let value): return T(value)
guard let result = T(exactly: value) else {
throw DecodingError.typeMismatch(
T.self,
.init(
codingPath: self.codingPath,
debugDescription: "Cannot fit \(value) into \(String(describing: T.self))"
)
)
}
return result
default: default:
throw DecodingError.typeMismatch( throw DecodingError.dataCorrupted(
T.self,
.init( .init(
codingPath: self.codingPath, codingPath: self.codingPath,
debugDescription: "Expected an int, but got \(self.value.debugDataTypeDescription)" debugDescription: "Expected an int, but got \(self.value.debugDataTypeDescription)"
) ))
)
} }
} }
} }

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import MessagePack import MessagePack

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import MessagePack import MessagePack
@ -49,6 +49,11 @@ extension _PklDecoder {
throw error("Expected an array at slot 2, but got \(value[1].debugDataTypeDescription)") throw error("Expected an array at slot 2, but got \(value[1].debugDataTypeDescription)")
} }
self.members = members self.members = members
} else if value.count == 3 {
guard pklType == .pair else {
throw error("Expected to find a Pair type marker, but found \(pklType)")
}
self.members = Array(value[1...2])
} else { } else {
throw error("Expected 2 or 3 values, but found \(value.count)") throw error("Expected 2 or 3 values, but found \(value.count)")
} }

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
@ -36,14 +36,17 @@ public func withEvaluator<T>(_ action: (Evaluator) async throws -> T) async thro
try await withEvaluator(options: .preconfigured, action) try await withEvaluator(options: .preconfigured, action)
} }
/// Like ``withProjectEvaluator(projectBaseURI:options:_:)``, but configured with preconfigured options. /// Like ``withProjectEvaluator(projectDir:options:_:)``, but configured with preconfigured otions.
/// ///
/// - Parameters: /// - Parameters:
/// - projectBaseURI: The base path containing the PklProject file. /// - projectDir: The directory containing the PklProject file.
/// - action: The action to perform. /// - action: The action to perform.
/// - Returns: The result of the action. /// - Returns: The result of the action.
public func withProjectEvaluator<T>(projectBaseURI: URL, _ action: (Evaluator) async throws -> T) async throws -> T { public func withProjectEvaluator<T>(
try await withProjectEvaluator(projectBaseURI: projectBaseURI, options: .preconfigured, action) projectDir: String,
_ action: (Evaluator) async throws -> T
) async throws -> T {
try await withProjectEvaluator(projectDir: projectDir, options: .preconfigured, action)
} }
/// Convenience method for initializing an evaluator from the project. /// Convenience method for initializing an evaluator from the project.
@ -53,17 +56,17 @@ public func withProjectEvaluator<T>(projectBaseURI: URL, _ action: (Evaluator) a
/// ///
/// After `action` completes, the evaluator is closed. /// After `action` completes, the evaluator is closed.
/// - Parameters: /// - Parameters:
/// - projectBaseURI: The base path containing the PklProject file. /// - projectDir: The directory containing the PklProject file.
/// - options: The base options used to configure the evaluator. /// - options: The base options used to configure the evaluator.
/// - action: The action to perform. /// - action: The action to perform.
/// - Returns: The result of the action. /// - Returns: The result of the action.
public func withProjectEvaluator<T>( public func withProjectEvaluator<T>(
projectBaseURI: URL, projectDir: String,
options: EvaluatorOptions, options: EvaluatorOptions,
_ action: (Evaluator) async throws -> T _ action: (Evaluator) async throws -> T
) async throws -> T { ) async throws -> T {
try await withEvaluatorManager { manager in try await withEvaluatorManager { manager in
let evaluator = try await manager.newProjectEvaluator(projectBaseURI: projectBaseURI, options: options) let evaluator = try await manager.newProjectEvaluator(projectDir: projectDir, options: options)
return try await action(evaluator) return try await action(evaluator)
} }
} }

View File

@ -1,31 +1,22 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
import MessagePack import MessagePack
import SemanticVersion
#if os(Windows)
import WinSDK.System
let ENV_SEPARATOR=";"
let PKL_EXEC_NAME="pkl.exe"
#else
let ENV_SEPARATOR=":"
let PKL_EXEC_NAME="pkl"
#endif
/// Perfoms `action`, returns its result and then closes the manager. /// Perfoms `action`, returns its result and then closes the manager.
/// ///
/// - Parameter action: The action to perform /// - Parameter action: The action to perform
@ -46,47 +37,6 @@ public func withEvaluatorManager<T>(_ action: (EvaluatorManager) async throws ->
} }
} }
func getenv(_ key: String) -> String? {
#if os(Windows)
let key = key.lowercased()
return ProcessInfo.processInfo.environment.first { (envKey: String, _: String) in
key == envKey.lowercased()
}?.value
#else
return ProcessInfo.processInfo.environment[key]
#endif
}
/// Resolve the (CLI) command to invoke Pkl.
///
/// First, checks the `PKL_EXEC` environment variable. If that is not set, searches the `PATH` for a directory
/// containing `pkl`.
func getPklCommand() throws -> [String] {
if let exec = getenv("PKL_EXEC") {
return exec.components(separatedBy: " ")
}
guard let path = getenv("PATH") else {
throw PklError("Unable to read PATH environment variable.")
}
for dir in path.components(separatedBy: ENV_SEPARATOR) {
do {
let contents = try FileManager.default.contentsOfDirectory(atPath: dir)
if let pkl = contents.first(where: { $0 == PKL_EXEC_NAME }) {
let file = NSString.path(withComponents: [dir, pkl])
if FileManager.default.isExecutableFile(atPath: file) {
return [file]
}
}
} catch {
if error._domain == NSCocoaErrorDomain {
continue
}
throw error
}
}
throw PklError("Unable to find `pkl` command on PATH.")
}
/// Provides handlers for managing the lifecycles of Pkl evaluators. If binding to Pkl as a child process, an evaluator /// Provides handlers for managing the lifecycles of Pkl evaluators. If binding to Pkl as a child process, an evaluator
/// manager represents a single child process. /// manager represents a single child process.
/// ///
@ -105,11 +55,9 @@ public actor EvaluatorManager {
var isClosed: Bool = false var isClosed: Bool = false
var pklVersion: String?
// note; when our C bindings are released, change `init()` based on compiler flags. // note; when our C bindings are released, change `init()` based on compiler flags.
public init() { public init() {
self.init(transport: ServerMessageTransport()) self.init(transport: ChildProcessMessageTransport())
} }
// Used for testing only. // Used for testing only.
@ -124,31 +72,6 @@ public actor EvaluatorManager {
} }
} }
/// Get the semantic version as a String of the Pkl interpreter being used.
func getVersion() throws -> String {
if let pklVersion {
return pklVersion
}
let pklCommand = try getPklCommand()
let process = Process()
process.executableURL = URL(fileURLWithPath: pklCommand[0])
process.arguments = Array(pklCommand.dropFirst()) + ["--version"]
let pipe = Pipe()
process.standardOutput = pipe
debug("Spawning command \(pklCommand[0]) with arguments \(process.arguments!)")
try process.run()
guard let outputData = try pipe.fileHandleForReading.readToEnd(),
let output = String(data: outputData, encoding: .utf8)?.split(separator: " "),
output.count > 2,
output[0] == "Pkl" else {
throw PklError("Could not get version from Pkl binary")
}
self.pklVersion = String(output[1])
return self.pklVersion!
}
private func listenForIncomingMessages() async throws { private func listenForIncomingMessages() async throws {
for try await message in try self.transport.getMessages() { for try await message in try self.transport.getMessages() {
debug("EvaluatorManager got message \(message)") debug("EvaluatorManager got message \(message)")
@ -204,24 +127,24 @@ public actor EvaluatorManager {
/// - options: The options used to configure the evaluator. /// - options: The options used to configure the evaluator.
/// - action: The action to run with the evaluator. /// - action: The action to run with the evaluator.
public func withEvaluator<T>(options: EvaluatorOptions, _ action: (Evaluator) async throws -> T) async throws -> T { public func withEvaluator<T>(options: EvaluatorOptions, _ action: (Evaluator) async throws -> T) async throws -> T {
let evaluator = try await newEvaluator(options: options) let evalautor = try await newEvaluator(options: options)
var closed = false var closed = false
do { do {
let result = try await action(evaluator) let result = try await action(evalautor)
try await evaluator.close() try await evalautor.close()
closed = true closed = true
return result return result
} catch { } catch {
if !closed { if !closed {
try await evaluator.close() try await evalautor.close()
} }
throw error throw error
} }
} }
/// Convenience method for constructing a project evaluator with preconfigured base options. /// Convenience method for constructing a project evaluator with preconfigured base options.
public func withProjectEvaluator<T>(projectBaseURI: URL, _ action: (Evaluator) async throws -> T) async throws -> T { public func withProjectEvaluator<T>(projectDir: String, _ action: (Evaluator) async throws -> T) async throws -> T {
try await self.withProjectEvaluator(projectBaseURI: projectBaseURI, options: .preconfigured, action) try await self.withProjectEvaluator(projectDir: projectDir, options: .preconfigured, action)
} }
/// Constructs an evaluator that is configured by the project within the project dir. /// Constructs an evaluator that is configured by the project within the project dir.
@ -232,20 +155,20 @@ public actor EvaluatorManager {
/// After the action completes or throws, the evaluator is closed. /// After the action completes or throws, the evaluator is closed.
/// ///
/// - Parameters: /// - Parameters:
/// - projectBaseURI: The project base path that contains the PklProject file. /// - projectDir: The project directory that contains the PklProject file.
/// - options: The options used to configure the evaluator. /// - options: The options used to configure the evaluator.
/// - action: The action to run with the evaluator. /// - action: The action to run with the evaluator.
public func withProjectEvaluator<T>(projectBaseURI: URL, options: EvaluatorOptions, _ action: (Evaluator) async throws -> T) async throws -> T { public func withProjectEvaluator<T>(projectDir: String, options: EvaluatorOptions, _ action: (Evaluator) async throws -> T) async throws -> T {
let evaluator = try await newProjectEvaluator(projectBaseURI: projectBaseURI, options: options) let evalautor = try await newProjectEvaluator(projectDir: projectDir, options: options)
var closed = false var closed = false
do { do {
let result = try await action(evaluator) let result = try await action(evalautor)
try await evaluator.close() try await evalautor.close()
closed = true closed = true
return result return result
} catch { } catch {
if !closed { if !closed {
try await evaluator.close() try await evalautor.close()
} }
throw error throw error
} }
@ -253,21 +176,13 @@ public actor EvaluatorManager {
/// Creates a new evaluator with the provided options. /// Creates a new evaluator with the provided options.
/// ///
/// To create an evaluator that understands project dependencies, use /// To create an evaluator that understands project dependencies, use ``newProjectEvaluator(projectDir:options:)``.
/// ``newProjectEvaluator(projectBaseURI:options:)``.
/// ///
/// - Parameter options: The options used to configure the evaluator. /// - Parameter options: The options used to configure the evaluator.
public func newEvaluator(options: EvaluatorOptions) async throws -> Evaluator { public func newEvaluator(options: EvaluatorOptions) async throws -> Evaluator {
if self.isClosed { if self.isClosed {
throw PklError("The evaluator manager is closed") throw PklError("The evaluator manager is closed")
} }
let version = try SemanticVersion(getVersion())!
guard options.http == nil || version >= pklVersion0_26 else {
throw PklError("http options are not supported on Pkl versions lower than 0.26")
}
guard (options.externalModuleReaders == nil && options.externalResourceReaders == nil) || version >= pklVersion0_27 else {
throw PklError("external reader options are not supported on Pkl versions lower than 0.27")
}
let req = options.toMessage() let req = options.toMessage()
guard let response = try await ask(req) as? CreateEvaluatorResponse else { guard let response = try await ask(req) as? CreateEvaluatorResponse else {
throw PklBugError.invalidMessageCode( throw PklBugError.invalidMessageCode(
@ -294,15 +209,15 @@ public actor EvaluatorManager {
// Any `evaluatorSettings` set within the PklProject file overwrites any fields set on `options`. // Any `evaluatorSettings` set within the PklProject file overwrites any fields set on `options`.
/// ///
/// - Parameters: /// - Parameters:
/// - projectBaseURI: The project base path containing the `PklProject` file. /// - projectDir: The project directory containing the `PklProject` file.
/// - options: The base options used to configure the evaluator. /// - options: The base options used to configure the evaluator.
public func newProjectEvaluator(projectBaseURI: URL, options: EvaluatorOptions) async throws -> Evaluator { public func newProjectEvaluator(projectDir: String, options: EvaluatorOptions) async throws -> Evaluator {
if self.isClosed { if self.isClosed {
throw PklError("The evaluator manager is closed") throw PklError("The evaluator manager is closed")
} }
return try await self.withEvaluator(options: .preconfigured) { projectEvaluator in return try await self.withEvaluator(options: .preconfigured) { projectEvaluator in
let project = try await projectEvaluator.evaluateOutputValue( let project = try await projectEvaluator.evaluateOutputValue(
source: .path("\(projectBaseURI)/PklProject"), source: .path("\(projectDir)/PklProject"),
asType: Project.self asType: Project.self
) )
return try await self.newEvaluator(options: options.withProject(project)) return try await self.newEvaluator(options: options.withProject(project))
@ -372,13 +287,3 @@ enum PklBugError: Error {
case invalidEvaluatorId(String) case invalidEvaluatorId(String)
case unknownMessage(String) case unknownMessage(String)
} }
let pklVersion0_25 = SemanticVersion("0.25.0")!
let pklVersion0_26 = SemanticVersion("0.26.0")!
let pklVersion0_27 = SemanticVersion("0.27.0")!
let supportedPklVersions = [
pklVersion0_25,
pklVersion0_26,
pklVersion0_27,
]

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
@ -30,11 +30,8 @@ public struct EvaluatorOptions {
cacheDir: String? = nil, cacheDir: String? = nil,
outputFormat: String? = nil, outputFormat: String? = nil,
logger: Logger = Loggers.noop, logger: Logger = Loggers.noop,
projectBaseURI: URL? = nil, projectDir: String? = nil,
http: Http? = nil, declaredProjectDependencies: [String: ProjectDependency]? = nil
declaredProjectDependencies: [String: ProjectDependency]? = nil,
externalModuleReaders: [String: ExternalReader]? = nil,
externalResourceReaders: [String: ExternalReader]? = nil
) { ) {
self.allowedModules = allowedModules self.allowedModules = allowedModules
self.allowedResources = allowedResources self.allowedResources = allowedResources
@ -48,11 +45,8 @@ public struct EvaluatorOptions {
self.cacheDir = cacheDir self.cacheDir = cacheDir
self.outputFormat = outputFormat self.outputFormat = outputFormat
self.logger = logger self.logger = logger
self.projectBaseURI = projectBaseURI self.projectDir = projectDir
self.http = http
self.declaredProjectDependencies = declaredProjectDependencies self.declaredProjectDependencies = declaredProjectDependencies
self.externalModuleReaders = externalModuleReaders
self.externalResourceReaders = externalResourceReaders
} }
/// Regular expression patterns that control what modules are allowed to be imported in a Pkl program. /// Regular expression patterns that control what modules are allowed to be imported in a Pkl program.
@ -112,33 +106,15 @@ public struct EvaluatorOptions {
/// It is meant to be set by lower level logic in Swift code that first evaluates the PklProject, /// It is meant to be set by lower level logic in Swift code that first evaluates the PklProject,
/// which then configures ``EvaluatorOptions`` accordingly. /// which then configures ``EvaluatorOptions`` accordingly.
/// ///
/// To emulate the CLI's `--project-dir` flag, create an evaluator with ``withProjectEvaluator(projectBaseURI:_:)``, /// To emulate the CLI's `--project-dir` flag, create an evaluator with ``withProjectEvaluator(projectDir:_:)``,
/// or ``EvaluatorManager/newProjectEvaluator()``. /// or ``EvaluatorManager/newProjectEvaluator()``.
public var projectBaseURI: URL? public var projectDir: String?
/// Settings that control how Pkl talks to HTTP(S) servers. /// The set of dependencies available to modules within ``projectDir``.
/// ///
/// Added in Pkl 0.26. /// When importing dependencies, a `PklProject.deps.json` file must exist within ``projectDir``
/// These fields are ignored if targeting Pkl 0.25.
public var http: Http?
/// The set of dependencies available to modules within ``projectBaseURI``.
///
/// When importing dependencies, a `PklProject.deps.json` file must exist within ``projectBaseURI``
/// that contains the project's resolved dependencies. /// that contains the project's resolved dependencies.
public var declaredProjectDependencies: [String: ProjectDependency]? public var declaredProjectDependencies: [String: ProjectDependency]?
/// Registered external commands that implement module reader schemes.
///
/// Added in Pkl 0.27.
/// If the underlying Pkl does not support external readers, evaluation will fail when a registered scheme is used.
public var externalModuleReaders: [String: ExternalReader]?
/// Registered external commands that implement resource reader schemes.
///
/// Added in Pkl 0.27.
/// If the underlying Pkl does not support external readers, evaluation will fail when a registered scheme is used.
public var externalResourceReaders: [String: ExternalReader]?
} }
extension EvaluatorOptions { extension EvaluatorOptions {
@ -177,21 +153,18 @@ extension EvaluatorOptions {
rootDir: self.rootDir, rootDir: self.rootDir,
cacheDir: self.cacheDir, cacheDir: self.cacheDir,
outputFormat: self.outputFormat, outputFormat: self.outputFormat,
project: self.project(), project: self.project()
http: self.http,
externalModuleReaders: self.externalModuleReaders,
externalResourceReaders: self.externalResourceReaders
) )
} }
func project() -> ProjectOrDependency? { func project() -> ProjectOrDependency? {
guard let projectBaseURI else { guard let projectDir else {
return nil return nil
} }
return .init( return .init(
packageUri: nil, packageUri: nil,
type: "project", type: "project",
projectFileUri: "file://\(projectBaseURI)/PklProject", projectFileUri: "file://\(projectDir)/PklProject",
checksums: nil, checksums: nil,
dependencies: self.declaredProjectDependenciesToMessage(self.declaredProjectDependencies) dependencies: self.declaredProjectDependenciesToMessage(self.declaredProjectDependencies)
) )
@ -254,17 +227,28 @@ extension EvaluatorOptions {
/// Builds options that configures the evaluator with settings set on the project. /// Builds options that configures the evaluator with settings set on the project.
/// ///
/// Skips any settings that are nil. /// Skips any settings that are nil.
public func withProjectEvaluatorSettings(_ evaluatorSettings: PklEvaluatorSettings) -> EvaluatorOptions { public func withProjectEvaluatorSettings(_ evaluatorSettings: Project.EvaluatorSettings) -> EvaluatorOptions {
var options = self var options = self
options.properties = evaluatorSettings.externalProperties ?? self.properties if evaluatorSettings.externalProperties != nil {
options.env = evaluatorSettings.env ?? self.env options.properties = evaluatorSettings.externalProperties
options.allowedModules = evaluatorSettings.allowedModules ?? self.allowedModules }
options.allowedResources = evaluatorSettings.allowedResources ?? self.allowedResources if evaluatorSettings.env != nil {
options.cacheDir = evaluatorSettings.noCache != nil ? nil : (evaluatorSettings.moduleCacheDir ?? self.cacheDir) options.env = evaluatorSettings.env
options.rootDir = evaluatorSettings.rootDir ?? self.rootDir }
options.http = evaluatorSettings.http ?? self.http if evaluatorSettings.allowedModules != nil {
options.externalModuleReaders = evaluatorSettings.externalModuleReaders ?? options.externalModuleReaders options.allowedModules = evaluatorSettings.allowedModules
options.externalResourceReaders = evaluatorSettings.externalResourceReaders ?? options.externalResourceReaders }
if evaluatorSettings.allowedResources != nil {
options.allowedResources = evaluatorSettings.allowedResources
}
if evaluatorSettings.noCache == true {
options.cacheDir = nil
} else if evaluatorSettings.moduleCacheDir != nil {
options.cacheDir = evaluatorSettings.moduleCacheDir
}
if evaluatorSettings.rootDir != nil {
options.rootDir = evaluatorSettings.rootDir
}
return options return options
} }
@ -293,8 +277,7 @@ extension EvaluatorOptions {
/// Builds options with dependencies from the input project. /// Builds options with dependencies from the input project.
public func withProjectDependencies(_ project: Project) -> EvaluatorOptions { public func withProjectDependencies(_ project: Project) -> EvaluatorOptions {
var options = self var options = self
options.projectBaseURI = URL(string: project.projectFileUri)! options.projectDir = String(URL(string: project.projectFileUri)!.path.dropLast("/PklProject".count))
options.projectBaseURI?.deleteLastPathComponent()
options.declaredProjectDependencies = self.projectDependencies(project) options.declaredProjectDependencies = self.projectDependencies(project)
return options return options
} }

View File

@ -1,208 +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.
//===----------------------------------------------------------------------===//
import Foundation
import MessagePack
// Example usage:
// import PklSwift
// @main
// struct Main {
// static func main() async throws {
// let client = ExternalReaderClient(
// options: ExternalReaderClientOptions(
// resourceReaders: [MyResourceReader()]
// ))
// try await client.run()
// }
// }
public struct ExternalReaderClientOptions {
/// Reader to receive requests.
public var requestReader: Reader = FileHandle.standardInput
/// Writer to publish responses.
public var responseWriter: Writer = FileHandle.standardOutput
/// Readers that allow reading custom resources in Pkl.
public var moduleReaders: [ModuleReader] = []
/// Readers that allow importing custom modules in Pkl.
public var resourceReaders: [ResourceReader] = []
public init(
requestReader: Reader = FileHandle.standardInput,
responseWriter: Writer = FileHandle.standardOutput,
moduleReaders: [ModuleReader] = [],
resourceReaders: [ResourceReader] = []
) {
self.requestReader = requestReader
self.responseWriter = responseWriter
self.moduleReaders = moduleReaders
self.resourceReaders = resourceReaders
}
}
public class ExternalReaderClient {
private let moduleReaders: [ModuleReader]
private let resourceReaders: [ResourceReader]
private let transport: MessageTransport
public init(options: ExternalReaderClientOptions) {
self.moduleReaders = options.moduleReaders
self.resourceReaders = options.resourceReaders
self.transport = ExternalReaderMessageTransport(
reader: options.requestReader, writer: options.responseWriter
)
}
public func run() async throws {
for try await message in try self.transport.getMessages() {
switch message {
case let message as InitializeModuleReaderRequest:
try self.handleInitializeModuleReaderRequest(request: message)
case let message as InitializeResourceReaderRequest:
try self.handleInitializeResourceReaderRequest(request: message)
case let message as ReadModuleRequest:
try await self.handleReadModuleRequest(request: message)
case let message as ReadResourceRequest:
try await self.handleReadResourceRequest(request: message)
case let message as ListModulesRequest:
try await self.handleListModulesRequest(request: message)
case let message as ListResourcesRequest:
try await self.handleListResourcesRequest(request: message)
case _ as CloseExternalProcess:
self.close()
default:
throw PklBugError.unknownMessage("Got request for unknown message: \(message)")
}
}
}
public func close() {
self.transport.close()
}
func handleInitializeModuleReaderRequest(request: InitializeModuleReaderRequest) throws {
var response = InitializeModuleReaderResponse(requestId: request.requestId, spec: nil)
guard let reader = moduleReaders.first(where: { $0.scheme == request.scheme }) else {
try self.transport.send(response)
return
}
response.spec = reader.toMessage()
try self.transport.send(response)
}
func handleInitializeResourceReaderRequest(request: InitializeResourceReaderRequest) throws {
var response = InitializeResourceReaderResponse(requestId: request.requestId, spec: nil)
guard let reader = resourceReaders.first(where: { $0.scheme == request.scheme }) else {
try self.transport.send(response)
return
}
response.spec = reader.toMessage()
try self.transport.send(response)
}
func handleReadModuleRequest(request: ReadModuleRequest) async throws {
var response = ReadModuleResponse(
requestId: request.requestId,
evaluatorId: request.evaluatorId,
contents: nil,
error: nil
)
guard let reader = moduleReaders.first(where: { $0.scheme == request.uri.scheme }) else {
response.error = "No module reader found for scheme \(request.uri.scheme!)"
try self.transport.send(response)
return
}
do {
let result = try await reader.read(url: request.uri)
response.contents = result
try self.transport.send(response)
} catch {
response.error = "\(error)"
try self.transport.send(response)
}
}
func handleReadResourceRequest(request: ReadResourceRequest) async throws {
var response = ReadResourceResponse(
requestId: request.requestId,
evaluatorId: request.evaluatorId,
contents: nil,
error: nil
)
guard
let reader = resourceReaders.first(where: { $0.scheme == request.uri.scheme }) else {
response.error = "No resource reader found for scheme \(request.uri.scheme!)"
try self.transport.send(response)
return
}
do {
let result = try await reader.read(url: request.uri)
response.contents = result
try self.transport.send(response)
} catch {
response.error = "\(error)"
try self.transport.send(response)
}
}
func handleListModulesRequest(request: ListModulesRequest) async throws {
var response = ListModulesResponse(
requestId: request.requestId,
evaluatorId: request.evaluatorId,
pathElements: nil,
error: nil
)
guard let reader = moduleReaders.first(where: { $0.scheme == request.uri.scheme }) else {
response.error = "No module reader found for scheme \(request.uri.scheme!)"
try self.transport.send(response)
return
}
do {
let elems = try await reader.listElements(uri: request.uri)
response.pathElements = elems.map { $0.toMessage() }
try self.transport.send(response)
} catch {
response.error = "\(error)"
try self.transport.send(response)
}
}
func handleListResourcesRequest(request: ListResourcesRequest) async throws {
var response = ListResourcesResponse(
requestId: request.requestId,
evaluatorId: request.evaluatorId,
pathElements: nil,
error: nil
)
guard
let reader = resourceReaders.first(where: { $0.scheme == request.uri.scheme }) else {
response.error = "No resource reader found for scheme \(request.uri.scheme!)"
try self.transport.send(response)
return
}
do {
let elems = try await reader.listElements(uri: request.uri)
response.pathElements = elems.map { $0.toMessage() }
try self.transport.send(response)
} catch {
response.error = "\(error)"
try self.transport.send(response)
}
}
}

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
import MessagePack import MessagePack

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
import MessagePack import MessagePack
@ -62,8 +62,8 @@ enum MessageType: Int, Codable {
case CREATE_EVALUATOR_REQUEST = 0x20 case CREATE_EVALUATOR_REQUEST = 0x20
case CREATE_EVALUATOR_RESPONSE = 0x21 case CREATE_EVALUATOR_RESPONSE = 0x21
case CLOSE_EVALUATOR = 0x22 case CLOSE_EVALUATOR = 0x22
case EVALUATE_REQUEST = 0x23 case EVALUATOR_REQUEST = 0x23
case EVALUATE_RESPONSE = 0x24 case EVALUATOR_RESPOSNE = 0x24
case LOG_MESSAGE = 0x25 case LOG_MESSAGE = 0x25
case READ_RESOURCE_REQUEST = 0x26 case READ_RESOURCE_REQUEST = 0x26
case READ_RESOURCE_RESPONSE = 0x27 case READ_RESOURCE_RESPONSE = 0x27
@ -73,11 +73,6 @@ enum MessageType: Int, Codable {
case LIST_RESOURCES_RESPONSE = 0x2B case LIST_RESOURCES_RESPONSE = 0x2B
case LIST_MODULES_REQUEST = 0x2C case LIST_MODULES_REQUEST = 0x2C
case LIST_MODULES_RESPONSE = 0x2D case LIST_MODULES_RESPONSE = 0x2D
case INITIALIZE_MODULE_READER_REQUEST = 0x2E
case INITIALIZE_MODULE_READER_RESPONSE = 0x2F
case INITIALIZE_RESOURCE_READER_REQUEST = 0x30
case INITIALIZE_RESOURCE_READER_RESPONSE = 0x31
case CLOSE_EXTERNAL_PROCESS = 0x32
} }
extension MessageType { extension MessageType {
@ -90,9 +85,9 @@ extension MessageType {
case is CloseEvaluatorRequest: case is CloseEvaluatorRequest:
return MessageType.CLOSE_EVALUATOR return MessageType.CLOSE_EVALUATOR
case is EvaluateRequest: case is EvaluateRequest:
return MessageType.EVALUATE_REQUEST return MessageType.EVALUATOR_REQUEST
case is EvaluateResponse: case is EvaluateResponse:
return MessageType.EVALUATE_RESPONSE return MessageType.EVALUATOR_RESPOSNE
case is LogMessage: case is LogMessage:
return MessageType.LOG_MESSAGE return MessageType.LOG_MESSAGE
case is ListResourcesRequest: case is ListResourcesRequest:
@ -107,16 +102,6 @@ extension MessageType {
return MessageType.READ_MODULE_RESPONSE return MessageType.READ_MODULE_RESPONSE
case is ReadResourceResponse: case is ReadResourceResponse:
return MessageType.READ_RESOURCE_RESPONSE return MessageType.READ_RESOURCE_RESPONSE
case is InitializeModuleReaderRequest:
return MessageType.INITIALIZE_MODULE_READER_REQUEST
case is InitializeModuleReaderResponse:
return MessageType.INITIALIZE_MODULE_READER_RESPONSE
case is InitializeResourceReaderRequest:
return MessageType.INITIALIZE_RESOURCE_READER_REQUEST
case is InitializeResourceReaderResponse:
return MessageType.INITIALIZE_RESOURCE_READER_RESPONSE
case is CloseExternalProcess:
return MessageType.CLOSE_EXTERNAL_PROCESS
default: default:
preconditionFailure("Unreachable code") preconditionFailure("Unreachable code")
} }
@ -137,9 +122,6 @@ struct CreateEvaluatorRequest: ClientRequestMessage {
var cacheDir: String? var cacheDir: String?
var outputFormat: String? var outputFormat: String?
var project: ProjectOrDependency? var project: ProjectOrDependency?
var http: Http?
var externalModuleReaders: [String: ExternalReader]?
var externalResourceReaders: [String: ExternalReader]?
} }
struct ProjectOrDependency: Codable { struct ProjectOrDependency: Codable {
@ -248,25 +230,3 @@ struct LogMessage: ServerOneWayMessage {
// NOTE: not guaranteed to conform to URL. This might have been transformed by a stack frame transformer. // NOTE: not guaranteed to conform to URL. This might have been transformed by a stack frame transformer.
let frameUri: String let frameUri: String
} }
struct InitializeModuleReaderRequest: ServerRequestMessage {
var requestId: Int64
let scheme: String
}
struct InitializeModuleReaderResponse: ClientResponseMessage {
var requestId: Int64
var spec: ModuleReaderSpec?
}
struct InitializeResourceReaderRequest: ServerRequestMessage {
var requestId: Int64
let scheme: String
}
struct InitializeResourceReaderResponse: ClientResponseMessage {
var requestId: Int64
var spec: ResourceReaderSpec?
}
struct CloseExternalProcess: ServerOneWayMessage {}

View File

@ -1,22 +1,21 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
import MessagePack import MessagePack
import SemanticVersion
protocol MessageTransport { protocol MessageTransport {
/// Send a message to the Pkl server. /// Send a message to the Pkl server.
@ -31,104 +30,35 @@ protocol MessageTransport {
extension Pipe: Reader { extension Pipe: Reader {
public func read(into: UnsafeMutableRawBufferPointer) throws -> Int { public func read(into: UnsafeMutableRawBufferPointer) throws -> Int {
try fileHandleForReading.read(into: into) let data = try fileHandleForReading.read(upToCount: into.count)
if data == nil {
return 0
}
data!.copyBytes(to: into)
return data!.count
} }
public func close() throws { public func close() throws {
try fileHandleForReading.close() fileHandleForReading.closeFile()
}
}
extension FileHandle: Reader {
public func read(into: UnsafeMutableRawBufferPointer) throws -> Int {
guard let data = try read(upToCount: into.count) else { return 0 }
data.copyBytes(to: into)
return data.count
}
public func close() throws {
closeFile()
} }
} }
extension Pipe: Writer { extension Pipe: Writer {
public func write(_ buffer: UnsafeRawBufferPointer) throws { public func write(_ buffer: UnsafeRawBufferPointer) throws {
try fileHandleForWriting.write(buffer) try fileHandleForWriting.write(contentsOf: buffer)
}
}
extension FileHandle: Writer {
public func write(_ buffer: UnsafeRawBufferPointer) throws {
try self.write(contentsOf: buffer)
}
}
/// A ``MessageTransport`` base class that implements core message handling logic
public class BaseMessageTransport: MessageTransport {
var reader: Reader!
var writer: Writer!
var encoder: MessagePackEncoder!
var decoder: MessagePackDecoder!
var running: Bool { true }
func send(_ message: ClientMessage) throws {
debug("Sending message: \(message)")
let messageType = MessageType.getMessageType(message)
try self.encoder.encodeArrayHeader(2)
try self.encoder.encode(messageType)
try self.encoder.encode(message)
}
fileprivate func decodeMessage(_ messageType: MessageType) throws -> ServerMessage {
switch messageType {
case MessageType.READ_MODULE_REQUEST:
return try self.decoder.decode(as: ReadModuleRequest.self)
case MessageType.READ_RESOURCE_REQUEST:
return try self.decoder.decode(as: ReadResourceRequest.self)
case MessageType.LIST_MODULES_REQUEST:
return try self.decoder.decode(as: ListModulesRequest.self)
case MessageType.LIST_RESOURCES_REQUEST:
return try self.decoder.decode(as: ListResourcesRequest.self)
default:
throw PklBugError.unknownMessage("Received unexpected message: \(messageType)")
}
}
func close() {}
func getMessages() throws -> AsyncThrowingStream<ServerMessage, Error> {
AsyncThrowingStream { continuation in
Task {
while self.running {
do {
let arrayLength = try decoder.decodeArrayLength()
assert(arrayLength == 2)
let code = try decoder.decode(as: MessageType.self)
let message = try decodeMessage(code)
debug("Received message: \(message)")
continuation.yield(message)
} catch {
if self.running {
continuation.finish(throwing: error)
}
}
}
continuation.finish()
}
}
} }
} }
/// A ``MessageTransport`` that sends and receives messages by spawning Pkl as a child process. /// A ``MessageTransport`` that sends and receives messages by spawning Pkl as a child process.
public class ServerMessageTransport: BaseMessageTransport { public class ChildProcessMessageTransport: MessageTransport {
var reader: Pipe!
var writer: Pipe!
var encoder: MessagePackEncoder!
var decoder: MessagePackDecoder!
var process: Process? var process: Process?
let pklCommand: [String]? let pklCommand: [String]?
override var running: Bool { self.process?.isRunning == true } convenience init() {
override convenience init() {
self.init(pklCommand: nil) self.init(pklCommand: nil)
} }
@ -136,6 +66,32 @@ public class ServerMessageTransport: BaseMessageTransport {
self.pklCommand = pklCommand self.pklCommand = pklCommand
} }
private func getPklCommand() throws -> [String] {
if let exec = ProcessInfo.processInfo.environment["PKL_EXEC"] {
return exec.components(separatedBy: " ")
}
guard let path = ProcessInfo.processInfo.environment["PATH"] else {
throw PklError("Unable to find `pkl` command on PATH.")
}
for dir in path.components(separatedBy: ":") {
do {
let contents = try FileManager.default.contentsOfDirectory(atPath: dir)
if let pkl = contents.first(where: { $0 == "pkl" }) {
let file = NSString.path(withComponents: [dir, pkl])
if FileManager.default.isExecutableFile(atPath: file) {
return [file]
}
}
} catch {
if error._domain == NSCocoaErrorDomain {
continue
}
throw error
}
}
throw PklError("Unable to find `pkl` command on PATH.")
}
private func ensureProcessStarted() throws { private func ensureProcessStarted() throws {
if self.process?.isRunning == true { return } if self.process?.isRunning == true { return }
let pklCommand = try getPklCommand() let pklCommand = try getPklCommand()
@ -144,8 +100,8 @@ public class ServerMessageTransport: BaseMessageTransport {
var arguments = Array(pklCommand.dropFirst()) var arguments = Array(pklCommand.dropFirst())
arguments.append("server") arguments.append("server")
self.process!.arguments = arguments self.process!.arguments = arguments
self.reader = Pipe() self.reader = .init()
self.writer = Pipe() self.writer = .init()
self.encoder = .init(writer: self.writer) self.encoder = .init(writer: self.writer)
self.decoder = .init(reader: self.reader) self.decoder = .init(reader: self.reader)
self.process!.standardOutput = self.reader self.process!.standardOutput = self.reader
@ -154,25 +110,17 @@ public class ServerMessageTransport: BaseMessageTransport {
try self.process!.run() try self.process!.run()
} }
override func send(_ message: ClientMessage) throws { func send(_ message: ClientMessage) throws {
try self.ensureProcessStarted() try self.ensureProcessStarted()
try super.send(message) debug("Sending message: \(message)")
let messageType = MessageType.getMessageType(message)
try self.encoder.encodeArrayHeader(2)
try self.encoder.encode(messageType)
try self.encoder.encode(message)
} }
override fileprivate func decodeMessage(_ messageType: MessageType) throws -> ServerMessage { func close() {
switch messageType {
case MessageType.CREATE_EVALUATOR_RESPONSE:
return try self.decoder.decode(as: CreateEvaluatorResponse.self)
case MessageType.EVALUATE_RESPONSE:
return try self.decoder.decode(as: EvaluateResponse.self)
case MessageType.LOG_MESSAGE:
return try self.decoder.decode(as: LogMessage.self)
default:
return try super.decodeMessage(messageType)
}
}
override func close() {
if self.process == nil { if self.process == nil {
return return
} }
@ -188,38 +136,45 @@ public class ServerMessageTransport: BaseMessageTransport {
self.process = nil self.process = nil
} }
override func getMessages() throws -> AsyncThrowingStream<ServerMessage, Error> { private func decodeMessage(_ messageType: MessageType) throws -> ServerMessage {
try self.ensureProcessStarted()
return try super.getMessages()
}
}
public class ExternalReaderMessageTransport: BaseMessageTransport {
override var running: Bool { self._running }
private var _running = true
init(reader: Reader, writer: Writer) {
super.init()
self.reader = reader
self.writer = writer
self.encoder = .init(writer: self.writer)
self.decoder = .init(reader: self.reader)
}
override fileprivate func decodeMessage(_ messageType: MessageType) throws -> ServerMessage {
switch messageType { switch messageType {
case MessageType.INITIALIZE_MODULE_READER_REQUEST: case MessageType.CREATE_EVALUATOR_RESPONSE:
return try self.decoder.decode(as: InitializeModuleReaderRequest.self) return try self.decoder.decode(as: CreateEvaluatorResponse.self)
case MessageType.INITIALIZE_RESOURCE_READER_REQUEST: case MessageType.EVALUATOR_RESPOSNE:
return try self.decoder.decode(as: InitializeResourceReaderRequest.self) return try self.decoder.decode(as: EvaluateResponse.self)
case MessageType.CLOSE_EXTERNAL_PROCESS: case MessageType.READ_MODULE_REQUEST:
return try self.decoder.decode(as: CloseExternalProcess.self) return try self.decoder.decode(as: ReadModuleRequest.self)
case MessageType.LOG_MESSAGE:
return try self.decoder.decode(as: LogMessage.self)
case MessageType.READ_RESOURCE_REQUEST:
return try self.decoder.decode(as: ReadResourceRequest.self)
case MessageType.LIST_MODULES_REQUEST:
return try self.decoder.decode(as: ListModulesRequest.self)
case MessageType.LIST_RESOURCES_REQUEST:
return try self.decoder.decode(as: ListResourcesRequest.self)
default: default:
return try super.decodeMessage(messageType) fatalError("Unreachable code")
} }
} }
override func close() { func getMessages() throws -> AsyncThrowingStream<ServerMessage, Error> {
self._running = false try self.ensureProcessStarted()
return AsyncThrowingStream { continuation in
Task {
while self.process?.isRunning == true {
do {
let arrayLength = try decoder.decodeArrayLength()
assert(arrayLength == 2)
let code = try decoder.decode(as: MessageType.self)
let message = try decodeMessage(code)
debug("Received message: \(message)")
continuation.yield(message)
} catch {
continuation.finish(throwing: error)
}
}
continuation.finish()
}
}
} }
} }

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
@ -36,7 +36,7 @@ extension ModuleSource {
/// - Parameter path: The file path component. /// - Parameter path: The file path component.
public static func path(_ path: String) -> ModuleSource { public static func path(_ path: String) -> ModuleSource {
let path = resolvePaths(path) let path = resolvePaths(path)
return ModuleSource(uri: URL(fileURLWithPath: path), text: nil) return ModuleSource(uri: URL(string: "file://\(path)")!, text: nil)
} }
/// Creates a synthetic ``ModuleSource`` with the given text. /// Creates a synthetic ``ModuleSource`` with the given text.

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation

View File

@ -1,114 +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.
//===----------------------------------------------------------------------===//
/// The Swift representation of standard library module `pkl.EvaluatorSettings`.
public struct PklEvaluatorSettings: Decodable, Hashable {
let externalProperties: [String: String]?
let env: [String: String]?
let allowedModules: [String]?
let allowedResources: [String]?
let noCache: Bool?
let modulePath: [String]?
let timeout: Duration?
let moduleCacheDir: String?
let rootDir: String?
let http: Http?
/// Added in Pkl 0.27
let externalModuleReaders: [String: ExternalReader]?
/// Added in Pkl 0.27
let externalResourceReaders: [String: ExternalReader]?
/// Whether to format messages and test results with ANSI color colors.
///
/// Added in Pkl 0.27
let color: PklEvaluatorSettingsColor?
}
public enum PklEvaluatorSettingsColor: String, CaseIterable, Decodable, Hashable {
/// Never format.
case never
/// Format if the process' stdin, stdout, or stderr are connected to a console.
case auto
/// Always format.
case always
}
/// Settings that control how Pkl talks to HTTP(S) servers.
public struct Http: Codable, Hashable {
/// PEM format certificates to trust when making HTTP requests.
///
/// If empty, Pkl will trust its own built-in certificates.
var caCertificates: [UInt8]?
/// Configuration of the HTTP proxy to use.
///
/// If `nil`, uses the operating system's proxy configuration.
/// Configuration of the HTTP proxy to use.
var proxy: Proxy?
}
/// Settings that control how Pkl talks to HTTP proxies.
public struct Proxy: Codable, Hashable {
/// The proxy to use for HTTP(S) connections.
///
/// Only HTTP proxies are supported.
/// The address must start with `"http://"`, and cannot contain anything other than a host and an optional port.
///
/// Example:
/// ```
/// "http://my.proxy.example.com:5080"
/// ```
var address: String?
/// Hosts to which all connections should bypass a proxy.
///
///
/// Values can be either hostnames, or IP addresses.
/// IP addresses can optionally be provided using
/// [CIDR notation](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation).
///
/// The value `"*"` is a wildcard that disables proxying for all hosts.
///
/// A hostname matches all subdomains.
/// For example, `example.com` matches `foo.example.com`, but not `fooexample.com`.
/// A hostname that is prefixed with a dot matches the hostname itself,
/// so `.example.com` matches `example.com`.
///
/// Hostnames do not match their resolved IP addresses.
/// For example, the hostname `localhost` will not match `127.0.0.1`.
///
/// Optionally, a port can be specified.
/// If a port is omitted, all ports are matched.
///
/// Example:
///
/// ```
/// [ "127.0.0.1",
/// "169.254.0.0/16",
/// "example.com",
/// "localhost:5050" ]
/// ```
var noProxy: [String]?
}
public struct ExternalReader: Codable, Hashable {
var executable: String
var arguments: [String]? = nil
}

View File

@ -1,26 +1,28 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation
/// The Swift representation of `pkl.Project` /// The Swift representation of `pkl.Project`
public struct Project: PklRegisteredType, Hashable, DependencyDeclaredInProjectFile { public struct Project: PklRegisteredType, Hashable, DependencyDeclaredInProjectFile {
public static let registeredIdentifier: String = "pkl.Project" public static var registeredIdentifier: String = "pkl.Project"
let package: Package? let package: Package?
let evaluatorSettings: PklEvaluatorSettings let evaluatorSettings: Project.EvaluatorSettings
let projectFileUri: String let projectFileUri: String
@ -50,7 +52,7 @@ extension Project: Decodable {
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let dec = try decoder.container(keyedBy: PklCodingKey.self) let dec = try decoder.container(keyedBy: PklCodingKey.self)
let package = try dec.decode(Package?.self, forKey: PklCodingKey(stringValue: "package")!) let package = try dec.decode(Package?.self, forKey: PklCodingKey(stringValue: "package")!)
let evaluatorSettings = try dec.decode(PklEvaluatorSettings.self, forKey: PklCodingKey(stringValue: "evaluatorSettings")!) let evaluatorSettings = try dec.decode(EvaluatorSettings.self, forKey: PklCodingKey(stringValue: "evaluatorSettings")!)
let projectFileUri = try dec.decode(String.self, forKey: PklCodingKey(stringValue: "projectFileUri")!) let projectFileUri = try dec.decode(String.self, forKey: PklCodingKey(stringValue: "projectFileUri")!)
let tests = try dec.decode([String].self, forKey: PklCodingKey(stringValue: "tests")!) let tests = try dec.decode([String].self, forKey: PklCodingKey(stringValue: "tests")!)
let dependencies = try dec.decode([String: PklAny].self, forKey: PklCodingKey(stringValue: "dependencies")!) let dependencies = try dec.decode([String: PklAny].self, forKey: PklCodingKey(stringValue: "dependencies")!)
@ -68,7 +70,7 @@ extension Project: Decodable {
extension Project { extension Project {
/// The Swift representation of `pkl.Project#RemoteDependency` /// The Swift representation of `pkl.Project#RemoteDependency`
public struct RemoteDependency: PklRegisteredType, DependencyDeclaredInProjectFile, Decodable, Hashable { public struct RemoteDependency: PklRegisteredType, DependencyDeclaredInProjectFile, Decodable, Hashable {
public static let registeredIdentifier: String = "pkl.Project#RemoteDependency" public static var registeredIdentifier: String = "pkl.Project#RemoteDependency"
let uri: String let uri: String
let checksums: Checksums? let checksums: Checksums?
@ -76,7 +78,7 @@ extension Project {
/// The Swift representation of `pkl.Project#Package` /// The Swift representation of `pkl.Project#Package`
public struct Package: PklRegisteredType, Hashable { public struct Package: PklRegisteredType, Hashable {
public static let registeredIdentifier: String = "pkl.Project#Package" public static var registeredIdentifier: String = "pkl.Project#Package"
let name: String let name: String
let baseUri: String let baseUri: String
@ -96,11 +98,16 @@ extension Project {
let uri: String let uri: String
} }
@available( /// The Swift representation of `pkl.Project#EvaluatorSettings
*, public struct EvaluatorSettings: Decodable, Hashable {
deprecated, let externalProperties: [String: String]?
message: "Replaced by PklEvaluatorSettings, independent of Project", let env: [String: String]?
renamed: "PklEvaluatorSettings" let allowedModules: [String]?
) let allowedResources: [String]?
public typealias EvaluatorSettings = PklEvaluatorSettings let noCache: Bool?
let modulePath: [String]?
let timeout: Duration?
let moduleCacheDir: String?
let rootDir: String?
}
} }

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
@ -35,8 +35,8 @@ public protocol BaseReader {
/// birds:catalog/swallow.pkl /// birds:catalog/swallow.pkl
/// ``` /// ```
/// ///
/// The first URI conveys name "swallow.pkl" within parent "/catalog/". The second URI /// The first URI conveys name "fred.pkl" within parent "/persons/". The second URI
/// conveys the name "catalog/swallow.pkl" with no hierarchical meaning. /// conveys the name "persons/fred.pkl" with no hierarchical meaning.
var hasHierarchicalUris: Bool { get } var hasHierarchicalUris: Bool { get }
/// Returns elements at a specified path. /// Returns elements at a specified path.
@ -107,11 +107,6 @@ public struct PathElement {
/// Whether the element is a directory or not. /// Whether the element is a directory or not.
public let isDirectory: Bool public let isDirectory: Bool
public init(name: String, isDirectory: Bool) {
self.name = name
self.isDirectory = isDirectory
}
} }
extension PathElement { extension PathElement {

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import MessagePack import MessagePack
import PklSwiftInternals import PklSwiftInternals

View File

@ -1,20 +1,25 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
#if os(Linux)
import Glibc
#else
import Darwin.C
#endif
let pklDebug = ProcessInfo.processInfo.environment["PKL_DEBUG"] let pklDebug = ProcessInfo.processInfo.environment["PKL_DEBUG"]
@ -75,7 +80,7 @@ public func mapEquals<K>(map1: [K: any DynamicallyEquatable], map2: [K: any Dyna
public func resolvePaths(_ paths: String...) -> String { public func resolvePaths(_ paths: String...) -> String {
var result = FileManager.default.currentDirectoryPath var result = FileManager.default.currentDirectoryPath
for path in paths { for path in paths {
if path.starts(with: "/") || URL(fileURLWithPath: path).path == path { if path.starts(with: "/") {
result = path result = path
} else { } else {
result = NSString.path(withComponents: [result, path]) result = NSString.path(withComponents: [result, path])
@ -85,12 +90,3 @@ public func resolvePaths(_ paths: String...) -> String {
} }
public let absoluteUriRegex = try! Regex("\\w+:") public let absoluteUriRegex = try! Regex("\\w+:")
public func tempDir() throws -> URL {
try (FileManager.default.url(for: .itemReplacementDirectory, in: .userDomainMask, appropriateFor: URL(fileURLWithPath: "/"), create: true))
}
public func tempFile(suffix: String) throws -> URL {
let fileName = ProcessInfo.processInfo.globallyUniqueString + suffix
return try (tempDir()).appendingPathComponent(fileName)
}

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //

View File

@ -1,18 +1,12 @@
/* //
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. // This source file is part of the Swift.org open source project
* //
* Licensed under the Apache License, Version 2.0 (the "License"); // Copyright (c) 2024 Apple Inc. and the Swift project authors
* you may not use this file except in compliance with the License. // Licensed under Apache License v2.0 with Runtime Library Exception
* You may obtain a copy of the License at //
* // See https://swift.org/LICENSE.txt for license information
* https://www.apache.org/licenses/LICENSE-2.0 // See https://swift.org/CONTRIBUTORS.txt for Swift project authors
* //
* 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.
*/
#include "Discovery.h" #include "Discovery.h"

View File

@ -1,18 +1,12 @@
/* //
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. // This source file is part of the Swift.org open source project
* //
* Licensed under the Apache License, Version 2.0 (the "License"); // Copyright (c) 2024 Apple Inc. and the Swift project authors
* you may not use this file except in compliance with the License. // Licensed under Apache License v2.0 with Runtime Library Exception
* You may obtain a copy of the License at //
* // See https://swift.org/LICENSE.txt for license information
* https://www.apache.org/licenses/LICENSE-2.0 // See https://swift.org/CONTRIBUTORS.txt for Swift project authors
* //
* 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.
*/
#if !defined(PKLS_DEFINES_H) #if !defined(PKLS_DEFINES_H)
#define PKLS_DEFINES_H #define PKLS_DEFINES_H

View File

@ -1,18 +1,12 @@
/* //
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. // This source file is part of the Swift.org open source project
* //
* Licensed under the Apache License, Version 2.0 (the "License"); // Copyright (c) 2024 Apple Inc. and the Swift project authors
* you may not use this file except in compliance with the License. // Licensed under Apache License v2.0 with Runtime Library Exception
* You may obtain a copy of the License at //
* // See https://swift.org/LICENSE.txt for license information
* https://www.apache.org/licenses/LICENSE-2.0 // See https://swift.org/CONTRIBUTORS.txt for Swift project authors
* //
* 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.
*/
#if !defined(PKLS_DISCOVERY_H) #if !defined(PKLS_DISCOVERY_H)
#define PKLS_DISCOVERY_H #define PKLS_DISCOVERY_H

View File

@ -6,7 +6,7 @@ public enum GeneratorSettings {}
extension GeneratorSettings { extension GeneratorSettings {
/// Settings used to configure code generation. /// Settings used to configure code generation.
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "pkl.swift.GeneratorSettings" public static var registeredIdentifier: String = "pkl.swift.GeneratorSettings"
/// The set of modules to turn into Swift code. /// The set of modules to turn into Swift code.
/// ///

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import ArgumentParser import ArgumentParser
import Foundation import Foundation
@ -77,6 +77,11 @@ struct PklGenSwift: AsyncParsableCommand {
) )
var pklInputModules: [String] = [] var pklInputModules: [String] = []
func tempFile() -> URL {
let fileName = ProcessInfo.processInfo.globallyUniqueString + ".pkl"
return URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
}
private func generateScriptUrl() -> String { private func generateScriptUrl() -> String {
if let generateScript = self.generateScript { if let generateScript = self.generateScript {
return URL(fileURLWithPath: generateScript).path return URL(fileURLWithPath: generateScript).path

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation import Foundation
import PklSwift import PklSwift
@ -41,6 +41,11 @@ public struct PklSwiftGenerator {
} }
} }
private func tempFile() -> URL {
let fileName = ProcessInfo.processInfo.globallyUniqueString + ".pkl"
return URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
}
private mutating func runModule(evaluator: Evaluator, pklInputModule: String) async throws { private mutating func runModule(evaluator: Evaluator, pklInputModule: String) async throws {
let out = resolvePaths(self.settings.outputPath ?? ".out") let out = resolvePaths(self.settings.outputPath ?? ".out")
let moduleToEvaluate = """ let moduleToEvaluate = """
@ -50,7 +55,7 @@ public struct PklSwiftGenerator {
moduleToGenerate = theModule moduleToGenerate = theModule
""" """
let tempFile = try tempFile(suffix: ".pkl") let tempFile = tempFile()
try moduleToEvaluate.write(to: tempFile, atomically: true, encoding: .utf8) try moduleToEvaluate.write(to: tempFile, atomically: true, encoding: .utf8)
let files = try await evaluator.evaluateOutputFiles(source: .url(tempFile)) let files = try await evaluator.evaluateOutputFiles(source: .url(tempFile))
for (filename, contents) in files { for (filename, contents) in files {

View File

@ -1,51 +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.
//===----------------------------------------------------------------------===//
import Foundation
import PklSwift
@main
struct TestExternalReader {
static func main() async throws {
let client = ExternalReaderClient(
options: ExternalReaderClientOptions(
resourceReaders: [FibReader()]
))
try await client.run()
}
}
struct FibReader: ResourceReader {
var scheme: String { "fib" }
var isGlobbable: Bool { false }
var hasHierarchicalUris: Bool { false }
func listElements(uri: URL) async throws -> [PathElement] { throw PklError("not implemented") }
func read(url: URL) async throws -> [UInt8] {
let key = url.absoluteString.dropFirst(self.scheme.count + 1)
guard let n = Int(key), n > 0 else {
throw PklError("input uri must be in format fib:<positive integer>")
}
return Array(String(fibonacci(n: n)).utf8)
}
}
func fibonacci(n: Int) -> Int {
var (a, b) = (0, 1)
for _ in 0..<n {
(a, b) = (b, a + b)
}
return a
}

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import XCTest import XCTest

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import XCTest import XCTest

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import XCTest import XCTest

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import PklSwift import PklSwift
import XCTest import XCTest

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import XCTest import XCTest
@ -43,11 +43,6 @@ final class PklDecoderTests: XCTestCase {
XCTAssertEqual(value, 42) XCTAssertEqual(value, 42)
} }
func testDecodeInt8Overflow() throws {
let bytes: [UInt8] = [0xD2, 0xFF, 0x00, 0x00, 0x00]
XCTAssertThrowsError(try PklDecoder.decode(Int8.self, from: bytes), "Cannot fit -16777216 into Int8")
}
func testDecodeString() throws { func testDecodeString() throws {
let bytes: [UInt8] = [ let bytes: [UInt8] = [
0xD9, 0x27, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6B, 0x20, 0x66, 0x6F, 0x78, 0xD9, 0x27, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6B, 0x20, 0x66, 0x6F, 0x78,

View File

@ -1,20 +1,20 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import SemanticVersion import Foundation
import XCTest import XCTest
@testable import PklSwift @testable import PklSwift
@ -55,10 +55,10 @@ class EvaluatorManagerTest: XCTestCase {
let manager1 = EvaluatorManager() let manager1 = EvaluatorManager()
let manager2 = EvaluatorManager() let manager2 = EvaluatorManager()
let manager3 = EvaluatorManager() let manager3 = EvaluatorManager()
async let evaluator1 = try manager1.newEvaluator(options: .preconfigured).evaluateOutputText(source: .text("res = \"evaluator 1\"")) async let evalautor1 = try manager1.newEvaluator(options: .preconfigured).evaluateOutputText(source: .text("res = \"evaluator 1\""))
async let evaluator2 = try manager2.newEvaluator(options: .preconfigured).evaluateOutputText(source: .text("res = \"evaluator 2\"")) async let evalautor2 = try manager2.newEvaluator(options: .preconfigured).evaluateOutputText(source: .text("res = \"evaluator 2\""))
async let evaluator3 = try manager3.newEvaluator(options: .preconfigured).evaluateOutputText(source: .text("res = \"evaluator 3\"")) async let evalautor3 = try manager3.newEvaluator(options: .preconfigured).evaluateOutputText(source: .text("res = \"evaluator 3\""))
let (result1, result2, result3) = try await (evaluator1, evaluator2, evaluator3) let (result1, result2, result3) = try await (evalautor1, evalautor2, evalautor3)
XCTAssertEqual(result1, "res = \"evaluator 1\"\n") XCTAssertEqual(result1, "res = \"evaluator 1\"\n")
XCTAssertEqual(result2, "res = \"evaluator 2\"\n") XCTAssertEqual(result2, "res = \"evaluator 2\"\n")
XCTAssertEqual(result3, "res = \"evaluator 3\"\n") XCTAssertEqual(result3, "res = \"evaluator 3\"\n")

View File

@ -1,22 +1,22 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import Foundation
@testable import MessagePack @testable import MessagePack
@testable import PklSwift @testable import PklSwift
import SemanticVersion
import XCTest import XCTest
class TestLogger: Logger { class TestLogger: Logger {
@ -91,33 +91,6 @@ final class PklSwiftTests: XCTestCase {
XCTAssertEqual(output, "foo = 1\n") XCTAssertEqual(output, "foo = 1\n")
} }
func testVersionCoverage() async throws {
let output = try await SemanticVersion(EvaluatorManager().getVersion())!
XCTAssert(supportedPklVersions.contains { $0.major == output.major && $0.minor == output.minor })
}
func testCustomProxyOptions() async throws {
let version = try await SemanticVersion(EvaluatorManager().getVersion())!
let expected = version < pklVersion0_26
? "http options are not supported on Pkl versions lower than 0.26"
: "ConnectException: Error connecting to host `example.com`"
var options = EvaluatorOptions.preconfigured
options.http = .init(
caCertificates: nil,
proxy: .init(
address: "http://localhost:1",
noProxy: ["myhost.com:1337", "myotherhost.org:42"]
)
)
do {
let evaluator = try await manager.newEvaluator(options: options)
let _ = try await evaluator.evaluateOutputText(source: .uri("https://example.com")!)
XCTFail("Should have thrown an error")
} catch {
XCTAssert("\(error)".contains(expected))
}
}
func testCustomModuleReader() async throws { func testCustomModuleReader() async throws {
let reader = VirtualModuleReader( let reader = VirtualModuleReader(
read: { _ in read: { _ in
@ -305,10 +278,10 @@ final class PklSwiftTests: XCTestCase {
XCTAssertEqual(logger.logLines, [#"pkl: TRACE: "Hello there" = "Hello there" (repl:text)\#n"#]) XCTAssertEqual(logger.logLines, [#"pkl: TRACE: "Hello there" = "Hello there" (repl:text)\#n"#])
} }
// TODO: re-enable this test when packages are available // TODO re-enable this test when packages are available
// //
// func testWithProject() async throws { // func testWithProject() async throws {
// let project1Dir = (try tempDir()).appendingPathComponent("project1") // let project1Dir = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("project1")
// try FileManager.default.createDirectory(at: project1Dir, withIntermediateDirectories: true) // try FileManager.default.createDirectory(at: project1Dir, withIntermediateDirectories: true)
// try """ // try """
// amends "pkl:Project" // amends "pkl:Project"

View File

@ -1,65 +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.
//===----------------------------------------------------------------------===//
import SemanticVersion
import XCTest
@testable import PklSwift
class ExternalReaderClientTest: XCTestCase {
func testE2E() async throws {
let version = try await SemanticVersion(EvaluatorManager().getVersion())!
guard version >= pklVersion0_27 else {
throw XCTSkip("External readers require Pkl 0.27 or later.")
}
let tempDir = try tempDir()
let testFile = tempDir.appendingPathComponent("test.pkl")
try #"""
import "pkl:test"
fib5 = read("fib:5").text.toInt()
fib10 = read("fib:10").text.toInt()
fib20 = read("fib:20").text.toInt()
fibErrA = test.catch(() -> read("fib:%20"))
fibErrB = test.catch(() -> read("fib:abc"))
fibErrC = test.catch(() -> read("fib:-10"))
"""#.write(to: testFile, atomically: true, encoding: .utf8)
let expectedResult = """
fib5 = 5
fib10 = 55
fib20 = 6765
fibErrA = "I/O error reading resource `fib:%20`. IOException: PklError(message: \\"input uri must be in format fib:<positive integer>\\")"
fibErrB = "I/O error reading resource `fib:abc`. IOException: PklError(message: \\"input uri must be in format fib:<positive integer>\\")"
fibErrC = "I/O error reading resource `fib:-10`. IOException: PklError(message: \\"input uri must be in format fib:<positive integer>\\")"
"""
let opts = EvaluatorOptions(
allowedModules: ["file:", "repl:text"],
allowedResources: ["fib:", "prop:"],
externalResourceReaders: [
"fib": ExternalReader(executable: "./.build/debug/test-external-reader"),
]
)
try await withEvaluator(options: opts) { evaluator in
let result = try await evaluator.evaluateOutputText(source: .url(testFile))
XCTAssertEqual(result.trimmingCharacters(in: .whitespacesAndNewlines), expectedResult.trimmingCharacters(in: .whitespacesAndNewlines))
}
}
}

View File

@ -1,2 +1,3 @@
res1: Duration = 10.h res1: Pair<Int, String> = Pair(42, "Hello")
res2: DataSize = 1.2345.gib res2: Duration = 10.h
res3: DataSize = 1.2345.gib

View File

@ -5,7 +5,7 @@ public enum AnyType {}
extension AnyType { extension AnyType {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "AnyType" public static var registeredIdentifier: String = "AnyType"
public var bird: AnyHashable? public var bird: AnyHashable?
@ -63,7 +63,7 @@ extension AnyType {
} }
public struct Bird: PklRegisteredType, Decodable, Hashable { public struct Bird: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "AnyType#Bird" public static var registeredIdentifier: String = "AnyType#Bird"
public var species: String public var species: String

View File

@ -5,15 +5,18 @@ public enum ApiTypes {}
extension ApiTypes { extension ApiTypes {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "ApiTypes" public static var registeredIdentifier: String = "ApiTypes"
public var res1: Duration public var res1: Pair<Int, String>
public var res2: DataSize public var res2: Duration
public init(res1: Duration, res2: DataSize) { public var res3: DataSize
public init(res1: Pair<Int, String>, res2: Duration, res3: DataSize) {
self.res1 = res1 self.res1 = res1
self.res2 = res2 self.res2 = res2
self.res3 = res3
} }
} }

View File

@ -5,7 +5,7 @@ public enum Classes {}
extension Classes { extension Classes {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "Classes" public static var registeredIdentifier: String = "Classes"
public var animals: [Animal] public var animals: [Animal]
@ -15,7 +15,7 @@ extension Classes {
} }
public struct Animal: PklRegisteredType, Decodable, Hashable { public struct Animal: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "Classes#Animal" public static var registeredIdentifier: String = "Classes#Animal"
public var name: String public var name: String

View File

@ -5,7 +5,7 @@ public enum Collections {}
extension Collections { extension Collections {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "Collections" public static var registeredIdentifier: String = "Collections"
public var res1: [Int] public var res1: [Int]

View File

@ -5,7 +5,7 @@ public enum ExtendedModule {}
extension ExtendedModule { extension ExtendedModule {
public struct Module: OpenModule.Module { public struct Module: OpenModule.Module {
public static let registeredIdentifier: String = "ExtendedModule" public static var registeredIdentifier: String = "ExtendedModule"
public var foo: String public var foo: String

View File

@ -13,7 +13,7 @@ extension OpenModule {
public typealias Module = OpenModule_Module public typealias Module = OpenModule_Module
public struct ModuleImpl: Module { public struct ModuleImpl: Module {
public static let registeredIdentifier: String = "OpenModule" public static var registeredIdentifier: String = "OpenModule"
public var foo: String public var foo: String

View File

@ -7,9 +7,6 @@ public protocol UnionTypes_Animal: PklRegisteredType, DynamicallyEquatable, Hash
var name: String { get } var name: String { get }
} }
public protocol UnionTypes_Shape: PklRegisteredType, DynamicallyEquatable, Hashable {
}
extension UnionTypes { extension UnionTypes {
public enum Fruit: Decodable, Hashable { public enum Fruit: Decodable, Hashable {
case banana(Banana) case banana(Banana)
@ -17,9 +14,8 @@ extension UnionTypes {
case apple(Apple) case apple(Apple)
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer() let decoded = try decoder.singleValueContainer().decode(PklSwift.PklAny.self).value
let value = try container.decode(PklSwift.PklAny.self).value switch decoded {
switch value?.base {
case let decoded as Banana: case let decoded as Banana:
self = Fruit.banana(decoded) self = Fruit.banana(decoded)
case let decoded as Grape: case let decoded as Grape:
@ -31,14 +27,14 @@ extension UnionTypes {
Fruit.self, Fruit.self,
.init( .init(
codingPath: decoder.codingPath, codingPath: decoder.codingPath,
debugDescription: "Expected type Fruit, but got \(String(describing: value))" debugDescription: "Expected type Fruit, but got \(String(describing: decoded))"
) )
) )
} }
} }
} }
public enum City: String, CaseIterable, CodingKeyRepresentable, Decodable, Hashable { public enum City: String, CaseIterable, Decodable, Hashable {
case sanFrancisco = "San Francisco" case sanFrancisco = "San Francisco"
case tokyo = "Tokyo" case tokyo = "Tokyo"
case zurich = "Zurich" case zurich = "Zurich"
@ -50,9 +46,8 @@ extension UnionTypes {
case donkey(Donkey) case donkey(Donkey)
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer() let decoded = try decoder.singleValueContainer().decode(PklSwift.PklAny.self).value
let value = try container.decode(PklSwift.PklAny.self).value switch decoded {
switch value?.base {
case let decoded as Zebra: case let decoded as Zebra:
self = ZebraOrDonkey.zebra(decoded) self = ZebraOrDonkey.zebra(decoded)
case let decoded as Donkey: case let decoded as Donkey:
@ -62,7 +57,7 @@ extension UnionTypes {
ZebraOrDonkey.self, ZebraOrDonkey.self,
.init( .init(
codingPath: decoder.codingPath, codingPath: decoder.codingPath,
debugDescription: "Expected type ZebraOrDonkey, but got \(String(describing: value))" debugDescription: "Expected type ZebraOrDonkey, but got \(String(describing: decoded))"
) )
) )
} }
@ -85,9 +80,8 @@ extension UnionTypes {
} }
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer() let decoded = try decoder.singleValueContainer().decode(PklSwift.PklAny.self).value
let value = try container.decode(PklSwift.PklAny.self).value switch decoded {
switch value?.base {
case let decoded as any Animal: case let decoded as any Animal:
self = AnimalOrString.animal(decoded) self = AnimalOrString.animal(decoded)
case let decoded as String: case let decoded as String:
@ -97,7 +91,7 @@ extension UnionTypes {
AnimalOrString.self, AnimalOrString.self,
.init( .init(
codingPath: decoder.codingPath, codingPath: decoder.codingPath,
debugDescription: "Expected type AnimalOrString, but got \(String(describing: value))" debugDescription: "Expected type AnimalOrString, but got \(String(describing: decoded))"
) )
) )
} }
@ -113,116 +107,8 @@ extension UnionTypes {
} }
} }
public enum IntOrFloat: Decodable, Hashable {
case int(Int)
case float64(Float64)
private static func decodeNumeric(from decoder: Decoder, _ container: any SingleValueDecodingContainer) -> IntOrFloat? {
return (try? .int(container.decode(Int.self)))
?? (try? .float64(container.decode(Float64.self)))
}
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let decoded = IntOrFloat.decodeNumeric(from: decoder, container)
if decoded != nil {
self = decoded!
return
}
let value = try container.decode(PklSwift.PklAny.self).value
throw DecodingError.typeMismatch(
IntOrFloat.self,
.init(
codingPath: decoder.codingPath,
debugDescription: "Expected type IntOrFloat, but got \(String(describing: value))"
)
)
}
}
public enum Environment: String, CaseIterable, CodingKeyRepresentable, Decodable, Hashable {
case dev = "dev"
case prod = "prod"
case qa = "qa"
}
public enum AnimalOrShape: Decodable, Hashable {
case animal(any Animal)
case shape(any Shape)
public static func ==(lhs: AnimalOrShape, rhs: AnimalOrShape) -> Bool {
switch (lhs, rhs) {
case let (.animal(a), .animal(b)):
return a.isDynamicallyEqual(to: b)
case let (.shape(a), .shape(b)):
return a.isDynamicallyEqual(to: b)
default:
return false
}
}
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let value = try container.decode(PklSwift.PklAny.self).value
switch value?.base {
case let decoded as any Animal:
self = AnimalOrShape.animal(decoded)
case let decoded as any Shape:
self = AnimalOrShape.shape(decoded)
default:
throw DecodingError.typeMismatch(
AnimalOrShape.self,
.init(
codingPath: decoder.codingPath,
debugDescription: "Expected type AnimalOrShape, but got \(String(describing: value))"
)
)
}
}
public func hash(into hasher: inout Hasher) {
switch self {
case let .animal(value):
hasher.combine(value)
case let .shape(value):
hasher.combine(value)
}
}
}
public enum Numbers: Decodable, Hashable {
case int8(Int8)
case int16(Int16)
case int32(Int32)
case int(Int)
private static func decodeNumeric(from decoder: Decoder, _ container: any SingleValueDecodingContainer) -> Numbers? {
return (try? .int8(container.decode(Int8.self)))
?? (try? .int16(container.decode(Int16.self)))
?? (try? .int32(container.decode(Int32.self)))
?? (try? .int(container.decode(Int.self)))
}
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let decoded = Numbers.decodeNumeric(from: decoder, container)
if decoded != nil {
self = decoded!
return
}
let value = try container.decode(PklSwift.PklAny.self).value
throw DecodingError.typeMismatch(
Numbers.self,
.init(
codingPath: decoder.codingPath,
debugDescription: "Expected type Numbers, but got \(String(describing: value))"
)
)
}
}
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "UnionTypes" public static var registeredIdentifier: String = "UnionTypes"
public var fruit1: Fruit public var fruit1: Fruit
@ -246,26 +132,6 @@ extension UnionTypes {
public var animalOrString2: AnimalOrString public var animalOrString2: AnimalOrString
public var intOrFloat1: IntOrFloat
public var intOrFloat2: IntOrFloat
public var intOrFloat3: IntOrFloat
public var config: [Environment: String]
public var animalOrShape1: AnimalOrShape
public var animalOrShape2: AnimalOrShape
public var numbers1: Numbers
public var numbers2: Numbers
public var numbers3: Numbers
public var numbers4: Numbers
public init( public init(
fruit1: Fruit, fruit1: Fruit,
fruit2: Fruit, fruit2: Fruit,
@ -277,17 +143,7 @@ extension UnionTypes {
animal1: ZebraOrDonkey, animal1: ZebraOrDonkey,
animal2: ZebraOrDonkey, animal2: ZebraOrDonkey,
animalOrString1: AnimalOrString, animalOrString1: AnimalOrString,
animalOrString2: AnimalOrString, animalOrString2: AnimalOrString
intOrFloat1: IntOrFloat,
intOrFloat2: IntOrFloat,
intOrFloat3: IntOrFloat,
config: [Environment: String],
animalOrShape1: AnimalOrShape,
animalOrShape2: AnimalOrShape,
numbers1: Numbers,
numbers2: Numbers,
numbers3: Numbers,
numbers4: Numbers
) { ) {
self.fruit1 = fruit1 self.fruit1 = fruit1
self.fruit2 = fruit2 self.fruit2 = fruit2
@ -300,21 +156,11 @@ extension UnionTypes {
self.animal2 = animal2 self.animal2 = animal2
self.animalOrString1 = animalOrString1 self.animalOrString1 = animalOrString1
self.animalOrString2 = animalOrString2 self.animalOrString2 = animalOrString2
self.intOrFloat1 = intOrFloat1
self.intOrFloat2 = intOrFloat2
self.intOrFloat3 = intOrFloat3
self.config = config
self.animalOrShape1 = animalOrShape1
self.animalOrShape2 = animalOrShape2
self.numbers1 = numbers1
self.numbers2 = numbers2
self.numbers3 = numbers3
self.numbers4 = numbers4
} }
} }
public struct Banana: PklRegisteredType, Decodable, Hashable { public struct Banana: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "UnionTypes#Banana" public static var registeredIdentifier: String = "UnionTypes#Banana"
public var isRipe: Bool public var isRipe: Bool
@ -324,7 +170,7 @@ extension UnionTypes {
} }
public struct Grape: PklRegisteredType, Decodable, Hashable { public struct Grape: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "UnionTypes#Grape" public static var registeredIdentifier: String = "UnionTypes#Grape"
public var isUsedForWine: Bool public var isUsedForWine: Bool
@ -334,7 +180,7 @@ extension UnionTypes {
} }
public struct Apple: PklRegisteredType, Decodable, Hashable { public struct Apple: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "UnionTypes#Apple" public static var registeredIdentifier: String = "UnionTypes#Apple"
public var isRed: Bool public var isRed: Bool
@ -345,20 +191,8 @@ extension UnionTypes {
public typealias Animal = UnionTypes_Animal public typealias Animal = UnionTypes_Animal
public typealias Shape = UnionTypes_Shape
public struct Square: Shape {
public static let registeredIdentifier: String = "UnionTypes#Square"
public var corners: Int
public init(corners: Int) {
self.corners = corners
}
}
public struct Zebra: Animal { public struct Zebra: Animal {
public static let registeredIdentifier: String = "UnionTypes#Zebra" public static var registeredIdentifier: String = "UnionTypes#Zebra"
public var name: String public var name: String
@ -368,7 +202,7 @@ extension UnionTypes {
} }
public struct Donkey: Animal { public struct Donkey: Animal {
public static let registeredIdentifier: String = "UnionTypes#Donkey" public static var registeredIdentifier: String = "UnionTypes#Donkey"
public var name: String public var name: String

View File

@ -9,7 +9,7 @@ public protocol pkl_swift_example_Poly_Animal: pkl_swift_lib1_Being {
extension pkl_swift_example_Poly { extension pkl_swift_example_Poly {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "pkl.swift.example.Poly" public static var registeredIdentifier: String = "pkl.swift.example.Poly"
public var beings: [any pkl_swift_lib1.Being] public var beings: [any pkl_swift_lib1.Being]
@ -56,7 +56,7 @@ extension pkl_swift_example_Poly {
} }
public struct Dog: Animal { public struct Dog: Animal {
public static let registeredIdentifier: String = "pkl.swift.example.Poly#Dog" public static var registeredIdentifier: String = "pkl.swift.example.Poly#Dog"
public var barks: Bool public var barks: Bool
@ -103,7 +103,7 @@ extension pkl_swift_example_Poly {
public typealias Animal = pkl_swift_example_Poly_Animal public typealias Animal = pkl_swift_example_Poly_Animal
public struct AnimalImpl: Animal { public struct AnimalImpl: Animal {
public static let registeredIdentifier: String = "pkl.swift.example.Poly#Animal" public static var registeredIdentifier: String = "pkl.swift.example.Poly#Animal"
public var name: String public var name: String
@ -116,7 +116,7 @@ extension pkl_swift_example_Poly {
} }
public struct Bird: pkl_swift_lib1.Being { public struct Bird: pkl_swift_lib1.Being {
public static let registeredIdentifier: String = "pkl.swift.example.Poly#Bird" public static var registeredIdentifier: String = "pkl.swift.example.Poly#Bird"
public var name: String public var name: String

View File

@ -9,7 +9,7 @@ public protocol pkl_swift_lib1_Being: PklRegisteredType, DynamicallyEquatable, H
extension pkl_swift_lib1 { extension pkl_swift_lib1 {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "pkl.swift.lib1" public static var registeredIdentifier: String = "pkl.swift.lib1"
public init() {} public init() {}
} }

View File

@ -1,5 +1,3 @@
import "pkl:math"
class Banana { class Banana {
isRipe: Boolean isRipe: Boolean
} }
@ -20,12 +18,6 @@ typealias Fruit = Banana | Grape | Apple
typealias City = "San Francisco"|"Tokyo"|"Zurich"|"London" typealias City = "San Francisco"|"Tokyo"|"Zurich"|"London"
abstract class Shape
class Square extends Shape {
fixed corners: Int = 4
}
fruit1: Fruit = new Banana { fruit1: Fruit = new Banana {
isRipe = true isRipe = true
} }
@ -60,34 +52,4 @@ typealias AnimalOrString = Animal|String
animalOrString1: AnimalOrString = new Zebra {} animalOrString1: AnimalOrString = new Zebra {}
animalOrString2: AnimalOrString = "Zebra" animalOrString2: AnimalOrString = "Zebra"
typealias IntOrFloat = Int | Float
intOrFloat1: IntOrFloat = 5.0
intOrFloat2: IntOrFloat = 5.5
intOrFloat3: IntOrFloat = 128
typealias Environment = "dev"|"prod"|"qa"
config: Mapping<Environment, String> = new {
["dev"] = "Imaginary Service Company (ISC) configuration"
}
typealias AnimalOrShape = Animal|Shape
animalOrShape1: AnimalOrShape = new Donkey {}
animalOrShape2: AnimalOrShape = new Square {}
typealias Numbers = Int8 | Int16 | Int32 | Int
numbers1: Numbers = 5
numbers2: Numbers = 128
numbers3: Numbers = 32768
numbers4: Numbers = math.maxInt

View File

@ -1,18 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import PklSwift import PklSwift
import XCTest import XCTest
@ -77,8 +77,9 @@ class FixturesTest: XCTestCase {
XCTAssertEqual( XCTAssertEqual(
result, result,
ApiTypes.Module( ApiTypes.Module(
res1: .hours(10), res1: Pair(42, "Hello"),
res2: .gibibytes(1.2345) res2: .hours(10),
res3: .gibibytes(1.2345)
) )
) )
} }
@ -160,17 +161,7 @@ class FixturesTest: XCTestCase {
animal1: .zebra(UnionTypes.Zebra(name: "Zebra")), animal1: .zebra(UnionTypes.Zebra(name: "Zebra")),
animal2: .donkey(UnionTypes.Donkey(name: "Donkey")), animal2: .donkey(UnionTypes.Donkey(name: "Donkey")),
animalOrString1: .animal(UnionTypes.Zebra(name: "Zebra")), animalOrString1: .animal(UnionTypes.Zebra(name: "Zebra")),
animalOrString2: .string("Zebra"), animalOrString2: .string("Zebra")
intOrFloat1: .float64(5.0),
intOrFloat2: .float64(5.5),
intOrFloat3: .int(128),
config: [.dev : "Imaginary Service Company (ISC) configuration"],
animalOrShape1: .animal(UnionTypes.Donkey(name: "Donkey")),
animalOrShape2: .shape(UnionTypes.Square(corners: 4)),
numbers1: .int8(5),
numbers2: .int16(128),
numbers3: .int32(32768),
numbers4: .int(Int.max)
)) ))
} }
} }

View File

@ -1,34 +1,32 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
import SemanticVersion import Foundation
import XCTest import XCTest
@testable import PklSwift @testable import PklSwift
class ProjectTest: XCTestCase { class ProjectTest: XCTestCase {
func testLoadProject() async throws { func testLoadProject() async throws {
let version = try await SemanticVersion(EvaluatorManager().getVersion())! let tempDir = NSTemporaryDirectory()
let tempDir = try tempDir() try FileManager.default.createDirectory(atPath: tempDir + "/subdir", withIntermediateDirectories: true)
let subDir = tempDir.appendingPathComponent("subdir") let otherProjectFile = URL(fileURLWithPath: tempDir, isDirectory: true)
try FileManager.default.createDirectory(at: subDir, withIntermediateDirectories: true) .appendingPathComponent("subdir/PklProject")
let otherProjectFile = subDir.appendingPathComponent("PklProject")
try #""" try #"""
@ModuleInfo { minPklVersion = "0.25.0" }
amends "pkl:Project" amends "pkl:Project"
package { package {
@ -39,53 +37,8 @@ class ProjectTest: XCTestCase {
} }
"""#.write(to: otherProjectFile, atomically: true, encoding: .utf8) """#.write(to: otherProjectFile, atomically: true, encoding: .utf8)
let file = try (PklSwift.tempDir()).appendingPathComponent("PklProject") let file = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
.appendingPathComponent("PklProject")
let httpSetting = version < pklVersion0_26 ? "" : """
http {
proxy {
address = "http://localhost:1"
noProxy {
"example.com"
"foo.bar.org"
}
}
}
"""
let externalReaderSettings = version < pklVersion0_27 ? "" : """
externalModuleReaders {
["scheme1"] {
executable = "reader1"
}
["scheme2"] {
executable = "reader2"
arguments { "with"; "args" }
}
}
externalResourceReaders {
["scheme3"] {
executable = "reader3"
}
["scheme4"] {
executable = "reader4"
arguments { "with"; "args" }
}
}
"""
let colorSetting = version < pklVersion0_27 ? "" : #"color = "always""#
let httpExpectation = version < pklVersion0_26 ? nil : Http(
caCertificates: nil,
proxy: .init(address: "http://localhost:1", noProxy: ["example.com", "foo.bar.org"])
)
let externalModuleReadersExpectation = version < pklVersion0_27 ? nil : [
"scheme1": ExternalReader(executable: "reader1"),
"scheme2": ExternalReader(executable: "reader2", arguments: ["with", "args"]),
]
let externalResourceReadersExpectation = version < pklVersion0_27 ? nil : [
"scheme3": ExternalReader(executable: "reader3"),
"scheme4": ExternalReader(executable: "reader4", arguments: ["with", "args"]),
]
let color: PklEvaluatorSettingsColor? = version < pklVersion0_27 ? nil : .always
try #""" try #"""
amends "pkl:Project" amends "pkl:Project"
@ -130,9 +83,6 @@ class ProjectTest: XCTestCase {
timeout = 5.min timeout = 5.min
moduleCacheDir = "/bar/buzz" moduleCacheDir = "/bar/buzz"
rootDir = "/buzzy" rootDir = "/buzzy"
\#(externalReaderSettings)
\#(httpSetting)
\#(colorSetting)
} }
dependencies { dependencies {
@ -147,7 +97,7 @@ class ProjectTest: XCTestCase {
source: .url(file), source: .url(file),
asType: Project.self asType: Project.self
) )
let expectedSettings = PklSwift.PklEvaluatorSettings( let expectedSettings = PklSwift.Project.EvaluatorSettings(
externalProperties: ["myprop": "1"], externalProperties: ["myprop": "1"],
env: ["myenv": "2"], env: ["myenv": "2"],
allowedModules: ["foo:"], allowedModules: ["foo:"],
@ -156,11 +106,7 @@ class ProjectTest: XCTestCase {
modulePath: ["/bar/baz"], modulePath: ["/bar/baz"],
timeout: .minutes(5), timeout: .minutes(5),
moduleCacheDir: "/bar/buzz", moduleCacheDir: "/bar/buzz",
rootDir: "/buzzy", rootDir: "/buzzy"
http: httpExpectation,
externalModuleReaders: externalModuleReadersExpectation,
externalResourceReaders: externalResourceReadersExpectation,
color: color
) )
let expectedPackage = PklSwift.Project.Package( let expectedPackage = PklSwift.Project.Package(
name: "hawk", name: "hawk",
@ -214,11 +160,7 @@ class ProjectTest: XCTestCase {
modulePath: nil, modulePath: nil,
timeout: nil, timeout: nil,
moduleCacheDir: nil, moduleCacheDir: nil,
rootDir: nil, rootDir: nil
http: nil,
externalModuleReaders: nil,
externalResourceReaders: nil,
color: nil
), ),
projectFileUri: "\(otherProjectFile)", projectFileUri: "\(otherProjectFile)",
tests: [], tests: [],

View File

@ -1 +1 @@
0.4.2 0.2.3

View File

@ -9,7 +9,7 @@ public protocol Classes_Animal: PklRegisteredType, DynamicallyEquatable, Hashabl
extension Classes { extension Classes {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "Classes" public static var registeredIdentifier: String = "Classes"
public var animals: [any Animal] public var animals: [any Animal]
@ -38,7 +38,7 @@ extension Classes {
public typealias Animal = Classes_Animal public typealias Animal = Classes_Animal
public struct AnimalImpl: Animal { public struct AnimalImpl: Animal {
public static let registeredIdentifier: String = "Classes#Animal" public static var registeredIdentifier: String = "Classes#Animal"
public var name: String public var name: String

View File

@ -10,7 +10,7 @@ extension EmptyOpenModule {
public typealias Module = EmptyOpenModule_Module public typealias Module = EmptyOpenModule_Module
public struct ModuleImpl: Module { public struct ModuleImpl: Module {
public static let registeredIdentifier: String = "EmptyOpenModule" public static var registeredIdentifier: String = "EmptyOpenModule"
public init() {} public init() {}
} }

View File

@ -5,7 +5,7 @@ public enum Enums {}
extension Enums { extension Enums {
/// City is one of these four fantastic cities /// City is one of these four fantastic cities
public enum City: String, CaseIterable, CodingKeyRepresentable, Decodable, Hashable { public enum City: String, CaseIterable, Decodable, Hashable {
case sanFrancisco = "San Francisco" case sanFrancisco = "San Francisco"
case london = "London" case london = "London"
case zurich = "Zurich" case zurich = "Zurich"
@ -19,9 +19,8 @@ extension Enums {
case monkey(Monkey) case monkey(Monkey)
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer() let decoded = try decoder.singleValueContainer().decode(PklSwift.PklAny.self).value
let value = try container.decode(PklSwift.PklAny.self).value switch decoded {
switch value?.base {
case let decoded as Horse: case let decoded as Horse:
self = Animal.horse(decoded) self = Animal.horse(decoded)
case let decoded as Zebra: case let decoded as Zebra:
@ -33,7 +32,7 @@ extension Enums {
Animal.self, Animal.self,
.init( .init(
codingPath: decoder.codingPath, codingPath: decoder.codingPath,
debugDescription: "Expected type Animal, but got \(String(describing: value))" debugDescription: "Expected type Animal, but got \(String(describing: decoded))"
) )
) )
} }
@ -46,9 +45,8 @@ extension Enums {
case arrayString([String]) case arrayString([String])
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer() let decoded = try decoder.singleValueContainer().decode(PklSwift.PklAny.self).value
let value = try container.decode(PklSwift.PklAny.self).value switch decoded {
switch value?.base {
case let decoded as [String: String]: case let decoded as [String: String]:
self = DictOrArray.dictionaryStringString(decoded) self = DictOrArray.dictionaryStringString(decoded)
case let decoded as [String]: case let decoded as [String]:
@ -58,7 +56,7 @@ extension Enums {
DictOrArray.self, DictOrArray.self,
.init( .init(
codingPath: decoder.codingPath, codingPath: decoder.codingPath,
debugDescription: "Expected type DictOrArray, but got \(String(describing: value))" debugDescription: "Expected type DictOrArray, but got \(String(describing: decoded))"
) )
) )
} }
@ -71,9 +69,8 @@ extension Enums {
case string(String) case string(String)
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer() let decoded = try decoder.singleValueContainer().decode(PklSwift.PklAny.self).value
let value = try container.decode(PklSwift.PklAny.self).value switch decoded {
switch value?.base {
case let decoded as Horse: case let decoded as Horse:
self = HorseOrBug.horse(decoded) self = HorseOrBug.horse(decoded)
case let decoded as String: case let decoded as String:
@ -85,7 +82,7 @@ extension Enums {
HorseOrBug.self, HorseOrBug.self,
.init( .init(
codingPath: decoder.codingPath, codingPath: decoder.codingPath,
debugDescription: "Expected type HorseOrBug, but got \(String(describing: value))" debugDescription: "Expected type HorseOrBug, but got \(String(describing: decoded))"
) )
) )
} }
@ -97,9 +94,8 @@ extension Enums {
case zebra(Zebra) case zebra(Zebra)
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer() let decoded = try decoder.singleValueContainer().decode(PklSwift.PklAny.self).value
let value = try container.decode(PklSwift.PklAny.self).value switch decoded {
switch value?.base {
case let decoded as Horse?: case let decoded as Horse?:
self = MaybeHorseOrDefinitelyZebra.horse(decoded) self = MaybeHorseOrDefinitelyZebra.horse(decoded)
case let decoded as Zebra: case let decoded as Zebra:
@ -109,7 +105,7 @@ extension Enums {
MaybeHorseOrDefinitelyZebra.self, MaybeHorseOrDefinitelyZebra.self,
.init( .init(
codingPath: decoder.codingPath, codingPath: decoder.codingPath,
debugDescription: "Expected type MaybeHorseOrDefinitelyZebra, but got \(String(describing: value))" debugDescription: "Expected type MaybeHorseOrDefinitelyZebra, but got \(String(describing: decoded))"
) )
) )
} }
@ -117,7 +113,7 @@ extension Enums {
} }
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "Enums" public static var registeredIdentifier: String = "Enums"
/// City of tomorrow! /// City of tomorrow!
public var city: City public var city: City
@ -149,7 +145,7 @@ extension Enums {
} }
public struct Horse: PklRegisteredType, Decodable, Hashable { public struct Horse: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "Enums#Horse" public static var registeredIdentifier: String = "Enums#Horse"
public var neigh: Bool public var neigh: Bool
@ -159,7 +155,7 @@ extension Enums {
} }
public struct Zebra: PklRegisteredType, Decodable, Hashable { public struct Zebra: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "Enums#Zebra" public static var registeredIdentifier: String = "Enums#Zebra"
public var stripes: String public var stripes: String
@ -169,7 +165,7 @@ extension Enums {
} }
public struct Monkey: PklRegisteredType, Decodable, Hashable { public struct Monkey: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "Enums#Monkey" public static var registeredIdentifier: String = "Enums#Monkey"
public var tail: String public var tail: String

View File

@ -4,13 +4,13 @@ import PklSwift
public enum ExplicitlyCoolName {} public enum ExplicitlyCoolName {}
extension ExplicitlyCoolName { extension ExplicitlyCoolName {
public enum ConfigType: String, CaseIterable, CodingKeyRepresentable, Decodable, Hashable { public enum ConfigType: String, CaseIterable, Decodable, Hashable {
case one = "one" case one = "one"
case two = "two" case two = "two"
} }
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "ExplicitName" public static var registeredIdentifier: String = "ExplicitName"
public var MyCoolProp: SomethingVeryFunny public var MyCoolProp: SomethingVeryFunny
@ -24,7 +24,7 @@ extension ExplicitlyCoolName {
} }
public struct SomethingVeryFunny: PklRegisteredType, Decodable, Hashable { public struct SomethingVeryFunny: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "ExplicitName#SomethingFunny" public static var registeredIdentifier: String = "ExplicitName#SomethingFunny"
public init() {} public init() {}
} }

View File

@ -5,7 +5,7 @@ public enum ExtendModule {}
extension ExtendModule { extension ExtendModule {
public struct Module: MyModule.Module { public struct Module: MyModule.Module {
public static let registeredIdentifier: String = "ExtendModule" public static var registeredIdentifier: String = "ExtendModule"
public var bar: String public var bar: String

View File

@ -9,7 +9,7 @@ public protocol ExtendingOpenClass_MyOpenClass: PklRegisteredType, DynamicallyEq
extension ExtendingOpenClass { extension ExtendingOpenClass {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "ExtendingOpenClass" public static var registeredIdentifier: String = "ExtendingOpenClass"
public var res1: MyClass public var res1: MyClass
@ -22,7 +22,7 @@ extension ExtendingOpenClass {
} }
public struct MyClass: MyOpenClass { public struct MyClass: MyOpenClass {
public static let registeredIdentifier: String = "ExtendingOpenClass#MyClass" public static var registeredIdentifier: String = "ExtendingOpenClass#MyClass"
public var myBoolean: Bool public var myBoolean: Bool
@ -37,7 +37,7 @@ extension ExtendingOpenClass {
public typealias MyOpenClass = ExtendingOpenClass_MyOpenClass public typealias MyOpenClass = ExtendingOpenClass_MyOpenClass
public struct MyOpenClassImpl: MyOpenClass { public struct MyOpenClassImpl: MyOpenClass {
public static let registeredIdentifier: String = "ExtendingOpenClass#MyOpenClass" public static var registeredIdentifier: String = "ExtendingOpenClass#MyOpenClass"
public var myStr: String public var myStr: String
@ -47,7 +47,7 @@ extension ExtendingOpenClass {
} }
public struct MyClass2: lib3.GoGoGo { public struct MyClass2: lib3.GoGoGo {
public static let registeredIdentifier: String = "ExtendingOpenClass#MyClass2" public static var registeredIdentifier: String = "ExtendingOpenClass#MyClass2"
public var myBoolean: Bool public var myBoolean: Bool

View File

@ -9,7 +9,7 @@ public protocol ExtendsAbstractClass_A: PklRegisteredType, DynamicallyEquatable,
extension ExtendsAbstractClass { extension ExtendsAbstractClass {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "ExtendsAbstractClass" public static var registeredIdentifier: String = "ExtendsAbstractClass"
public var a: any A public var a: any A
@ -36,7 +36,7 @@ extension ExtendsAbstractClass {
public typealias A = ExtendsAbstractClass_A public typealias A = ExtendsAbstractClass_A
public struct B: A { public struct B: A {
public static let registeredIdentifier: String = "ExtendsAbstractClass#B" public static var registeredIdentifier: String = "ExtendsAbstractClass#B"
public var c: String public var c: String

View File

@ -13,7 +13,7 @@ public protocol Foo_Being: PklRegisteredType, DynamicallyEquatable, Hashable {
extension Foo { extension Foo {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "Foo" public static var registeredIdentifier: String = "Foo"
public var animals: [any Animal] public var animals: [any Animal]
@ -42,7 +42,7 @@ extension Foo {
public typealias Animal = Foo_Animal public typealias Animal = Foo_Animal
public struct AnimalImpl: Animal { public struct AnimalImpl: Animal {
public static let registeredIdentifier: String = "Foo#Animal" public static var registeredIdentifier: String = "Foo#Animal"
public var name: String public var name: String
@ -57,7 +57,7 @@ extension Foo {
public typealias Being = Foo_Being public typealias Being = Foo_Being
public struct Bird: Animal { public struct Bird: Animal {
public static let registeredIdentifier: String = "Foo#Bird" public static var registeredIdentifier: String = "Foo#Bird"
public var flies: Bool public var flies: Bool
@ -73,7 +73,7 @@ extension Foo {
} }
public struct Dog: Animal { public struct Dog: Animal {
public static let registeredIdentifier: String = "Foo#Dog" public static var registeredIdentifier: String = "Foo#Dog"
public var barks: Bool public var barks: Bool

View File

@ -5,7 +5,7 @@ public enum HiddenProperties {}
extension HiddenProperties { extension HiddenProperties {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "HiddenProperties" public static var registeredIdentifier: String = "HiddenProperties"
public var propC: String public var propC: String

View File

@ -5,7 +5,7 @@ public enum Imports {}
extension Imports { extension Imports {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "Imports" public static var registeredIdentifier: String = "Imports"
public var foo: Foo.Module public var foo: Foo.Module

View File

@ -11,7 +11,7 @@ extension MyModule {
public typealias Module = MyModule_Module public typealias Module = MyModule_Module
public struct ModuleImpl: Module { public struct ModuleImpl: Module {
public static let registeredIdentifier: String = "MyModule" public static var registeredIdentifier: String = "MyModule"
public var foo: String public var foo: String

View File

@ -11,7 +11,7 @@ extension Override2 {
public typealias Module = Override2_Module public typealias Module = Override2_Module
public struct ModuleImpl: Module { public struct ModuleImpl: Module {
public static let registeredIdentifier: String = "Override2" public static var registeredIdentifier: String = "Override2"
/// Doc comments /// Doc comments
public var foo: String public var foo: String
@ -22,7 +22,7 @@ extension Override2 {
} }
public struct MySubclass: Module { public struct MySubclass: Module {
public static let registeredIdentifier: String = "Override2#MySubclass" public static var registeredIdentifier: String = "Override2#MySubclass"
/// Doc comments /// Doc comments
public var foo: String public var foo: String

View File

@ -5,7 +5,7 @@ public enum TypeAliased {}
extension TypeAliased { extension TypeAliased {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "TypeAliased" public static var registeredIdentifier: String = "TypeAliased"
public var myMap: StringyMap public var myMap: StringyMap

View File

@ -4,14 +4,14 @@ import PklSwift
public enum UnionNameKeyword {} public enum UnionNameKeyword {}
extension UnionNameKeyword { extension UnionNameKeyword {
public enum `Type`: String, CaseIterable, CodingKeyRepresentable, Decodable, Hashable { public enum `Type`: String, CaseIterable, Decodable, Hashable {
case one = "one" case one = "one"
case two = "two" case two = "two"
case three = "three" case three = "three"
} }
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "UnionNameKeyword" public static var registeredIdentifier: String = "UnionNameKeyword"
public var type: `Type` public var type: `Type`

View File

@ -5,13 +5,13 @@ public enum com_example_ExtendedSimple {}
extension com_example_ExtendedSimple { extension com_example_ExtendedSimple {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "com.example.ExtendedSimple" public static var registeredIdentifier: String = "com.example.ExtendedSimple"
public init() {} public init() {}
} }
public struct ExtendedSimple: com_example_Simple.Person { public struct ExtendedSimple: com_example_Simple.Person {
public static let registeredIdentifier: String = "com.example.ExtendedSimple#ExtendedSimple" public static var registeredIdentifier: String = "com.example.ExtendedSimple#ExtendedSimple"
public var eyeColor: String public var eyeColor: String

View File

@ -15,7 +15,7 @@ public protocol com_example_Simple_OpenClassExtendingOpenClass: PklRegisteredTyp
extension com_example_Simple { extension com_example_Simple {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "com.example.Simple" public static var registeredIdentifier: String = "com.example.Simple"
/// This is truly a person. /// This is truly a person.
public var person: any Person public var person: any Person
@ -43,7 +43,7 @@ extension com_example_Simple {
public typealias Person = com_example_Simple_Person public typealias Person = com_example_Simple_Person
public struct PersonImpl: Person { public struct PersonImpl: Person {
public static let registeredIdentifier: String = "com.example.Simple#Person" public static var registeredIdentifier: String = "com.example.Simple#Person"
/// The name of the person /// The name of the person
public var theName: String public var theName: String
@ -63,7 +63,7 @@ extension com_example_Simple {
} }
public struct ThePerson: Person { public struct ThePerson: Person {
public static let registeredIdentifier: String = "com.example.Simple#ThePerson" public static var registeredIdentifier: String = "com.example.Simple#ThePerson"
public var the: String public var the: String
@ -89,7 +89,7 @@ extension com_example_Simple {
public typealias OpenClassExtendingOpenClass = com_example_Simple_OpenClassExtendingOpenClass public typealias OpenClassExtendingOpenClass = com_example_Simple_OpenClassExtendingOpenClass
public struct OpenClassExtendingOpenClassImpl: OpenClassExtendingOpenClass { public struct OpenClassExtendingOpenClassImpl: OpenClassExtendingOpenClass {
public static let registeredIdentifier: String = "com.example.Simple#OpenClassExtendingOpenClass" public static var registeredIdentifier: String = "com.example.Simple#OpenClassExtendingOpenClass"
public var someOtherProp: Bool? public var someOtherProp: Bool?
@ -99,7 +99,7 @@ extension com_example_Simple {
} }
public struct ClassWithReallyLongConstructor: PklRegisteredType, Decodable, Hashable { public struct ClassWithReallyLongConstructor: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "com.example.Simple#ClassWithReallyLongConstructor" public static var registeredIdentifier: String = "com.example.Simple#ClassWithReallyLongConstructor"
public var theProperty1: String public var theProperty1: String

View File

@ -11,7 +11,7 @@ extension lib3 {
public typealias GoGoGo = lib3_GoGoGo public typealias GoGoGo = lib3_GoGoGo
public struct GoGoGoImpl: GoGoGo { public struct GoGoGoImpl: GoGoGo {
public static let registeredIdentifier: String = "lib3#GoGoGo" public static var registeredIdentifier: String = "lib3#GoGoGo"
public var duck: String public var duck: String
@ -21,7 +21,7 @@ extension lib3 {
} }
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "lib3" public static var registeredIdentifier: String = "lib3"
public init() {} public init() {}
} }

View File

@ -9,7 +9,7 @@ public protocol override_Foo: PklRegisteredType, DynamicallyEquatable, Hashable
extension override { extension override {
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "override" public static var registeredIdentifier: String = "override"
public var foo: any Foo public var foo: any Foo
@ -36,7 +36,7 @@ extension override {
public typealias Foo = override_Foo public typealias Foo = override_Foo
public struct Bar: Foo { public struct Bar: Foo {
public static let registeredIdentifier: String = "override#Bar" public static var registeredIdentifier: String = "override#Bar"
public var myProp: String public var myProp: String

View File

@ -5,28 +5,28 @@ public enum union {}
extension union { extension union {
/// City; e.g. where people live /// City; e.g. where people live
public enum City: String, CaseIterable, CodingKeyRepresentable, Decodable, Hashable { public enum City: String, CaseIterable, Decodable, Hashable {
case sanFrancisco = "San Francisco" case sanFrancisco = "San Francisco"
case london = "London" case london = "London"
case = "上海" case = "上海"
} }
/// Locale that contains cities and towns /// Locale that contains cities and towns
public enum County: String, CaseIterable, CodingKeyRepresentable, Decodable, Hashable { public enum County: String, CaseIterable, Decodable, Hashable {
case sanFrancisco = "San Francisco" case sanFrancisco = "San Francisco"
case sanMateo = "San Mateo" case sanMateo = "San Mateo"
case yolo = "Yolo" case yolo = "Yolo"
} }
/// Noodles /// Noodles
public enum Noodles: String, CaseIterable, CodingKeyRepresentable, Decodable, Hashable { public enum Noodles: String, CaseIterable, Decodable, Hashable {
case = "拉面" case = "拉面"
case = "刀切面" case = "刀切面"
case 线 = "面线" case 线 = "面线"
case = "意大利面" case = "意大利面"
} }
public enum AccountDisposition: String, CaseIterable, CodingKeyRepresentable, Decodable, Hashable { public enum AccountDisposition: String, CaseIterable, Decodable, Hashable {
case empty = "" case empty = ""
case icloud3 = "icloud3" case icloud3 = "icloud3"
case prod = "prod" case prod = "prod"
@ -34,7 +34,7 @@ extension union {
} }
public struct Module: PklRegisteredType, Decodable, Hashable { public struct Module: PklRegisteredType, Decodable, Hashable {
public static let registeredIdentifier: String = "union" public static var registeredIdentifier: String = "union"
/// A city /// A city
public var city: City public var city: City

View File

@ -1,19 +1,18 @@
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
// 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.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// https://www.apache.org/licenses/LICENSE-2.0 // https://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//===----------------------------------------------------------------------===// // ===----------------------------------------------------------------------===//
/// Generates Swift sources from Pkl /// Generates Swift sources from Pkl
@swift.Module { name = "pkl_gen_swift" } @swift.Module { name = "pkl_gen_swift" }
@ModuleInfo { minPklVersion = "0.24.0" } @ModuleInfo { minPklVersion = "0.24.0" }

View File

@ -1,19 +1,3 @@
//===----------------------------------------------------------------------===//
// 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.
//===----------------------------------------------------------------------===//
/// Settings used to configure code generation. /// Settings used to configure code generation.
@swift.Module { name = "pkl_gen_swift" } @swift.Module { name = "pkl_gen_swift" }
@swift.Name { value = "GeneratorSettings" } @swift.Name { value = "GeneratorSettings" }

View File

@ -1,19 +1,3 @@
//===----------------------------------------------------------------------===//
// 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.
//===----------------------------------------------------------------------===//
amends "pkl:Project" amends "pkl:Project"
package { package {

View File

@ -1,4 +1,4 @@
{ {
"schemaVersion": 1, "schemaVersion": 1,
"resolvedDependencies": {} "resolvedDependencies": {}
} }

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