Compare commits

...

16 Commits
0.3.0 ... main

Author SHA1 Message Date
Daniel Chao d6f08700d6
Prepare 0.4.2 release (#48) 2025-04-14 10:09:19 -07:00
Daniel Chao cf45d102cb
Fix Swift mapping of ints within unions (#47)
This fixes an issue where a union with an int member cannot decode
any value that is out of the Int8 bounds.

Also: make SingleValueDecodingContainer throw `typeMismatch` errors
when the expected type doesn't match.
2025-02-26 09:12:56 -08:00
Daniel Chao c514843f01
Add pkl-lsp to ignored dirs (#46) 2025-02-26 07:13:12 -08:00
Daniel Chao 9c36448681
Make enums of string literals conform to CodingKeyRepresentable (#45)
Fixes an issue where mappings of enums fail to be decoded into Swift
2025-02-25 07:10:50 -08:00
Daniel Chao 799b6696d2
Swiftformat check (#43)
* Add makefile and CI rules to run the swift formatter
* Run swift format on all files
2025-02-24 19:09:46 -08:00
Kushal Pisavadia b7e694ea3c
Configure `hawkeye` to update license headers (#38)
Adds configuration to format/check license headers with hawkeye.

Also, runs the formatter on the repo.
2025-02-17 12:45:41 -08:00
Daniel Chao dda82f32a7
Add DocC auto generation (#41)
This will add pkl-swift docs to the Swift Package Index.

See: https://swiftpackageindex.com/blog/auto-generating-auto-hosting-and-auto-updating-docc-documentation

This also adds `swift-docc-plugin` as a dependency, which enables
running command `swift package generate-documentation --target PklSwift`.
2025-02-12 06:28:28 -08:00
Daniel Chao 3c5da314c9
Prepare 0.4.1 release (#40) 2025-02-04 09:53:29 -08:00
Daniel Chao b253e83f7b
Fix enum decoding (#39)
Fixes an issue where `5.0` in Pkl can possibly be cast to `Int`
2025-02-03 10:50:36 -08:00
Kushal Pisavadia f0bd189f48
Make sure CircleCI config is up-to-date (#37) 2025-02-03 13:43:40 +01:00
Daniel Chao c280a0e632
Add PR links (#34) 2025-01-24 08:10:27 -08:00
Daniel Chao 162bf61a96
Prepare 0.4.0 release (#33) 2025-01-23 08:42:40 -08:00
Daniel Chao 52d5fbc5e1
Add color to PklEvaluatorSettings (#32)
This adds a field that was added in Pkl 0.27
2025-01-23 06:59:31 -08:00
Josh B 64c66aea8e
Implement SPICE-0009 External Readers (#26)
* Add `EvaluatorOptions.externalModuleReaders` and `EvaluatorOptions.externalResourceReaders`.
* Add `ExternalReaderClient` to host the child process side of the external reader workflow.
2025-01-17 06:34:34 -08:00
Javier Cuesta 7d451c59cd
Make PathElement initializer explicitly public (#31)
Also, fix doc comments
2024-12-13 14:18:23 -08:00
Josh B 1d0bf43b4b
Fix temporary directory creation to avoid failing pkl-core tests (#28) 2024-12-04 16:54:32 +00:00
101 changed files with 1733 additions and 498 deletions

View File

@ -1,5 +1,5 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
// 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.
@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// ===----------------------------------------------------------------------===//
amends "package://pkg.pkl-lang.org/pkl-project-commons/pkl.impl.circleci@1.0.1#/PklCI.pkl"
amends "package://pkg.pkl-lang.org/pkl-project-commons/pkl.impl.circleci@1.1.1#/PklCI.pkl"
import "pkl:semver"
@ -47,7 +47,7 @@ local class PklDistribution {
}
local pklCurrent: PklDistribution = new {
version = "0.26.0"
version = "0.27.2"
}
local pklDistributions: Listing<PklDistribution> = new {
@ -133,6 +133,7 @@ jobs {
"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" }
@ -143,6 +144,34 @@ jobs {
}
}
["test-license-headers"] {
docker {
new {
image = "ghcr.io/korandoru/hawkeye"
}
}
steps {
"checkout"
new RunStep {
command = "/bin/hawkeye check --fail-if-unknown"
}
}
}
["test-format"] {
docker {
new {
image = "swift:5.9-rhel-ubi9"
}
}
steps {
"checkout"
new RunStep {
command = "make swiftformat-lint"
}
}
}
["pkl-gen-swift-macos"] {
macos {
xcode = "15.2.0"

View File

@ -18,6 +18,8 @@ jobs:
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:
@ -29,21 +31,23 @@ jobs:
resource_class: xlarge
docker:
- image: swift:5.9-rhel-ubi9
test-pkl-0-26-0:
test-pkl-0-27-2:
steps:
- checkout
- run:
command: |-
PKL=$(mktemp /tmp/pkl-0.26.0-XXXXXX)
curl -L "https://github.com/apple/pkl/releases/download/0.26.0/pkl-linux-amd64" > $PKL
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.26.0
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:
@ -55,6 +59,20 @@ jobs:
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:
steps:
- checkout
@ -108,11 +126,11 @@ jobs:
- checkout
- run:
command: |-
PKL=$(mktemp /tmp/pkl-0.26.0-XXXXXX)
curl -L "https://github.com/apple/pkl/releases/download/0.26.0/pkl-linux-amd64" > $PKL
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.26.0
name: Downloading pkl-0.27.2
- run:
command: $PKL_EXEC project package --skip-publish-check --output-path out/pkl-package/ codegen/src/
- persist_to_workspace:
@ -193,11 +211,15 @@ workflows:
- test-pkl-0-25-3:
requires:
- hold
- pr-approval/authenticate
- test-pkl-0-26-0:
- test-pkl-0-27-2:
requires:
- hold
- test-license-headers:
requires:
- hold
- test-format:
requires:
- hold
- pr-approval/authenticate
when:
matches:
value: << pipeline.git.branch >>
@ -205,7 +227,9 @@ workflows:
main:
jobs:
- test-pkl-0-25-3
- test-pkl-0-26-0
- test-pkl-0-27-2
- test-license-headers
- test-format
when:
equal:
- main
@ -218,7 +242,19 @@ workflows:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- test-pkl-0-26-0:
- 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:
branches:
ignore: /.*/
@ -227,7 +263,9 @@ workflows:
- pkl-package:
requires:
- test-pkl-0-25-3
- test-pkl-0-26-0
- test-pkl-0-27-2
- test-license-headers
- test-format
filters:
branches:
ignore: /.*/
@ -236,7 +274,9 @@ workflows:
- pkl-gen-swift-macos:
requires:
- test-pkl-0-25-3
- test-pkl-0-26-0
- test-pkl-0-27-2
- test-license-headers
- test-format
filters:
branches:
ignore: /.*/
@ -245,7 +285,9 @@ workflows:
- pkl-gen-swift-linux-amd64:
requires:
- test-pkl-0-25-3
- test-pkl-0-26-0
- test-pkl-0-27-2
- test-license-headers
- test-format
filters:
branches:
ignore: /.*/
@ -254,7 +296,9 @@ workflows:
- pkl-gen-swift-linux-aarch64:
requires:
- test-pkl-0-25-3
- test-pkl-0-26-0
- test-pkl-0-27-2
- test-license-headers
- test-format
filters:
branches:
ignore: /.*/

4
.gitignore vendored
View File

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

4
.spi.yml Normal file
View File

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

View File

@ -15,9 +15,8 @@
--guardelse same-line
--nevertrailing filter
--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
--disable spaceAroundOperators
--disable wrapMultilineStatementBraces
--disable wrapMultilineStatementBraces

31
DEVELOPMENT.adoc Normal file
View File

@ -0,0 +1,31 @@
= 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,3 +108,19 @@ pkl-gen-swift-release: $(PKL_GEN_SWIFT_RELEASE)
.PHONY: pkl-gen-swift-release-output
pkl-gen-swift-release-output:
@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

@ -18,6 +18,24 @@
"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",
"kind" : "remoteSourceControl",
@ -26,6 +44,15 @@
"revision" : "025bcb1165deab2e20d4eaba79967ce73013f496",
"version" : "1.2.1"
}
},
{
"identity" : "swiftformat",
"kind" : "remoteSourceControl",
"location" : "https://github.com/nicklockwood/SwiftFormat",
"state" : {
"revision" : "468a7d32dedc8d352c191594b3b45d9fd8ba291b",
"version" : "0.55.5"
}
}
],
"version" : 2

View File

@ -1,4 +1,20 @@
// 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
let package = Package(
@ -25,6 +41,10 @@ let package = Package(
.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/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: [
.target(
@ -48,6 +68,10 @@ let package = Package(
],
resources: [.embedInCode("Resources/VERSION.txt")]
),
.executableTarget(
name: "test-external-reader",
dependencies: ["PklSwift"]
),
.testTarget(
name: "PklSwiftTests",
dependencies: [

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
struct AnyCodingKey: CodingKey, Equatable {
let stringValue: String

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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
@ -44,10 +44,13 @@ public final class MessagePackEncoder {
try Box<Data>(data).encode(to: encoder)
case let date as Date:
try Box<Date>(date).encode(to: encoder)
case let bytes as [UInt8]:
try Box<[UInt8]>(bytes).encode(to: encoder)
case let url as URL:
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:
try value.encode(to: encoder)
}

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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
@ -304,8 +304,6 @@ extension _MessagePackEncoder.SingleValueContainer: SingleValueEncodingContainer
try self.encode(data)
case let date as Date:
try self.encode(date)
case let bytes as [UInt8]:
try self.encode(bytes)
case let url as URL:
try self.encode(url)
case let bool as Bool:
@ -334,9 +332,16 @@ extension _MessagePackEncoder.SingleValueContainer: SingleValueEncodingContainer
try self.encode(uint64)
case let num as any BinaryInteger & Encodable:
try self.encode(num)
case let bytes as [UInt8]:
guard type(of: value) == [UInt8].self else {
fallthrough
}
try self.encode(bytes)
default:
let writer: Writer = BufferWriter()
let encoder = _MessagePackEncoder()
encoder.userInfo = userInfo
encoder.codingPath = codingPath
try value.encode(to: encoder)
try encoder.write(into: writer)
let data = (writer as! BufferWriter).bytes

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
extension FixedWidthInteger {
init(bytes: [UInt8]) {

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
public protocol Writer {
/// Write the given bytes into an output somewhere.

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 MessagePack

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 MessagePack
@ -37,11 +37,13 @@ class PklSingleValueDecodingContainer: SingleValueDecodingContainer {
switch self.value {
case .bool(let value): return value
default:
throw DecodingError.dataCorrupted(
throw DecodingError.typeMismatch(
Bool.self,
.init(
codingPath: self.codingPath,
debugDescription: "Expected a boolean, but got \(self.value.debugDataTypeDescription)"
))
)
)
}
}
@ -49,11 +51,13 @@ class PklSingleValueDecodingContainer: SingleValueDecodingContainer {
switch self.value {
case .string(let value): return value
default:
throw DecodingError.dataCorrupted(
throw DecodingError.typeMismatch(
String.self,
.init(
codingPath: self.codingPath,
debugDescription: "Expected a string, but got \(self.value.debugDataTypeDescription)"
))
)
)
}
}
@ -61,11 +65,13 @@ class PklSingleValueDecodingContainer: SingleValueDecodingContainer {
switch self.value {
case .float(let value): return Double(value)
default:
throw DecodingError.dataCorrupted(
throw DecodingError.typeMismatch(
Double.self,
.init(
codingPath: self.codingPath,
debugDescription: "Expected a float, but got \(self.value.debugDataTypeDescription)"
))
)
)
}
}
@ -73,11 +79,13 @@ class PklSingleValueDecodingContainer: SingleValueDecodingContainer {
switch self.value {
case .float(let value): return Float(value)
default:
throw DecodingError.dataCorrupted(
throw DecodingError.typeMismatch(
Float.self,
.init(
codingPath: self.codingPath,
debugDescription: "Expected a float, but got \(self.value.debugDataTypeDescription)"
))
)
)
}
}
@ -124,7 +132,7 @@ class PklSingleValueDecodingContainer: SingleValueDecodingContainer {
func decode<T>(_ type: T.Type) throws -> T where T: Decodable {
if type == PklAny.self {
guard let result = try _PklDecoder.decodePolymorphic(value, codingPath: codingPath) else {
throw DecodingError.dataCorrupted(.init(codingPath: self.codingPath, debugDescription: "Tried to decode but got nil"))
throw DecodingError.typeMismatch(T.self, .init(codingPath: self.codingPath, debugDescription: "Tried to decode but got nil"))
}
return result as! T
}
@ -135,13 +143,25 @@ class PklSingleValueDecodingContainer: SingleValueDecodingContainer {
private func decodeBinaryInteger<T>() throws -> T where T: BinaryInteger {
switch self.value {
case .int(let value): return T(value)
case .int(let 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:
throw DecodingError.dataCorrupted(
throw DecodingError.typeMismatch(
T.self,
.init(
codingPath: self.codingPath,
debugDescription: "Expected an int, but got \(self.value.debugDataTypeDescription)"
))
)
)
}
}
}

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 MessagePack

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 MessagePack

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,29 +1,30 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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
import SemanticVersion
#if os(Windows)
import WinSDK.System
let ENV_SEPARATOR=";"
let PKL_EXEC_NAME="pkl.exe"
import WinSDK.System
let ENV_SEPARATOR=";"
let PKL_EXEC_NAME="pkl.exe"
#else
let ENV_SEPARATOR=":"
let PKL_EXEC_NAME="pkl"
let ENV_SEPARATOR=":"
let PKL_EXEC_NAME="pkl"
#endif
/// Perfoms `action`, returns its result and then closes the manager.
///
@ -46,14 +47,14 @@ public func withEvaluatorManager<T>(_ action: (EvaluatorManager) async throws ->
}
func getenv(_ key: String) -> String? {
#if os(Windows)
#if os(Windows)
let key = key.lowercased()
return ProcessInfo.processInfo.environment.first { (envKey: String, value: String) in
return key == envKey.lowercased()
return ProcessInfo.processInfo.environment.first { (envKey: String, _: String) in
key == envKey.lowercased()
}?.value
#else
#else
return ProcessInfo.processInfo.environment[key]
#endif
#endif
}
/// Resolve the (CLI) command to invoke Pkl.
@ -108,7 +109,7 @@ public actor EvaluatorManager {
// note; when our C bindings are released, change `init()` based on compiler flags.
public init() {
self.init(transport: ChildProcessMessageTransport())
self.init(transport: ServerMessageTransport())
}
// Used for testing only.
@ -264,6 +265,9 @@ public actor EvaluatorManager {
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()
guard let response = try await ask(req) as? CreateEvaluatorResponse else {
throw PklBugError.invalidMessageCode(
@ -371,8 +375,10 @@ enum PklBugError: Error {
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 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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
@ -32,7 +32,9 @@ public struct EvaluatorOptions {
logger: Logger = Loggers.noop,
projectBaseURI: URL? = nil,
http: Http? = nil,
declaredProjectDependencies: [String: ProjectDependency]? = nil
declaredProjectDependencies: [String: ProjectDependency]? = nil,
externalModuleReaders: [String: ExternalReader]? = nil,
externalResourceReaders: [String: ExternalReader]? = nil
) {
self.allowedModules = allowedModules
self.allowedResources = allowedResources
@ -49,6 +51,8 @@ public struct EvaluatorOptions {
self.projectBaseURI = projectBaseURI
self.http = http
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.
@ -123,6 +127,18 @@ public struct EvaluatorOptions {
/// When importing dependencies, a `PklProject.deps.json` file must exist within ``projectBaseURI``
/// that contains the project's resolved dependencies.
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 {
@ -162,7 +178,9 @@ extension EvaluatorOptions {
cacheDir: self.cacheDir,
outputFormat: self.outputFormat,
project: self.project(),
http: self.http
http: self.http,
externalModuleReaders: self.externalModuleReaders,
externalResourceReaders: self.externalResourceReaders
)
}
@ -245,6 +263,8 @@ extension EvaluatorOptions {
options.cacheDir = evaluatorSettings.noCache != nil ? nil : (evaluatorSettings.moduleCacheDir ?? self.cacheDir)
options.rootDir = evaluatorSettings.rootDir ?? self.rootDir
options.http = evaluatorSettings.http ?? self.http
options.externalModuleReaders = evaluatorSettings.externalModuleReaders ?? options.externalModuleReaders
options.externalResourceReaders = evaluatorSettings.externalResourceReaders ?? options.externalResourceReaders
return options
}

View File

@ -0,0 +1,208 @@
//===----------------------------------------------------------------------===//
// 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 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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
@ -62,8 +62,8 @@ enum MessageType: Int, Codable {
case CREATE_EVALUATOR_REQUEST = 0x20
case CREATE_EVALUATOR_RESPONSE = 0x21
case CLOSE_EVALUATOR = 0x22
case EVALUATOR_REQUEST = 0x23
case EVALUATOR_RESPONSE = 0x24
case EVALUATE_REQUEST = 0x23
case EVALUATE_RESPONSE = 0x24
case LOG_MESSAGE = 0x25
case READ_RESOURCE_REQUEST = 0x26
case READ_RESOURCE_RESPONSE = 0x27
@ -73,6 +73,11 @@ enum MessageType: Int, Codable {
case LIST_RESOURCES_RESPONSE = 0x2B
case LIST_MODULES_REQUEST = 0x2C
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 {
@ -85,9 +90,9 @@ extension MessageType {
case is CloseEvaluatorRequest:
return MessageType.CLOSE_EVALUATOR
case is EvaluateRequest:
return MessageType.EVALUATOR_REQUEST
return MessageType.EVALUATE_REQUEST
case is EvaluateResponse:
return MessageType.EVALUATOR_RESPONSE
return MessageType.EVALUATE_RESPONSE
case is LogMessage:
return MessageType.LOG_MESSAGE
case is ListResourcesRequest:
@ -102,6 +107,16 @@ extension MessageType {
return MessageType.READ_MODULE_RESPONSE
case is ReadResourceResponse:
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:
preconditionFailure("Unreachable code")
}
@ -123,6 +138,8 @@ struct CreateEvaluatorRequest: ClientRequestMessage {
var outputFormat: String?
var project: ProjectOrDependency?
var http: Http?
var externalModuleReaders: [String: ExternalReader]?
var externalResourceReaders: [String: ExternalReader]?
}
struct ProjectOrDependency: Codable {
@ -231,3 +248,25 @@ struct LogMessage: ServerOneWayMessage {
// NOTE: not guaranteed to conform to URL. This might have been transformed by a stack frame transformer.
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,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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
@ -31,35 +31,104 @@ protocol MessageTransport {
extension Pipe: Reader {
public func read(into: UnsafeMutableRawBufferPointer) throws -> Int {
let data = try fileHandleForReading.read(upToCount: into.count)
if data == nil {
return 0
}
data!.copyBytes(to: into)
return data!.count
try fileHandleForReading.read(into: into)
}
public func close() throws {
fileHandleForReading.closeFile()
try fileHandleForReading.close()
}
}
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 {
public func write(_ buffer: UnsafeRawBufferPointer) throws {
try fileHandleForWriting.write(contentsOf: buffer)
try fileHandleForWriting.write(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.
public class ChildProcessMessageTransport: MessageTransport {
var reader: Pipe!
var writer: Pipe!
var encoder: MessagePackEncoder!
var decoder: MessagePackDecoder!
public class ServerMessageTransport: BaseMessageTransport {
var process: Process?
let pklCommand: [String]?
convenience init() {
override var running: Bool { self.process?.isRunning == true }
override convenience init() {
self.init(pklCommand: nil)
}
@ -75,8 +144,8 @@ public class ChildProcessMessageTransport: MessageTransport {
var arguments = Array(pklCommand.dropFirst())
arguments.append("server")
self.process!.arguments = arguments
self.reader = .init()
self.writer = .init()
self.reader = Pipe()
self.writer = Pipe()
self.encoder = .init(writer: self.writer)
self.decoder = .init(reader: self.reader)
self.process!.standardOutput = self.reader
@ -85,17 +154,25 @@ public class ChildProcessMessageTransport: MessageTransport {
try self.process!.run()
}
func send(_ message: ClientMessage) throws {
override func send(_ message: ClientMessage) throws {
try self.ensureProcessStarted()
debug("Sending message: \(message)")
let messageType = MessageType.getMessageType(message)
try self.encoder.encodeArrayHeader(2)
try self.encoder.encode(messageType)
try self.encoder.encode(message)
try super.send(message)
}
func close() {
override fileprivate func decodeMessage(_ messageType: MessageType) throws -> ServerMessage {
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 {
return
}
@ -111,45 +188,38 @@ public class ChildProcessMessageTransport: MessageTransport {
self.process = nil
}
private func decodeMessage(_ messageType: MessageType) throws -> ServerMessage {
override func getMessages() throws -> AsyncThrowingStream<ServerMessage, Error> {
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 {
case MessageType.CREATE_EVALUATOR_RESPONSE:
return try self.decoder.decode(as: CreateEvaluatorResponse.self)
case MessageType.EVALUATOR_RESPONSE:
return try self.decoder.decode(as: EvaluateResponse.self)
case MessageType.READ_MODULE_REQUEST:
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)
case MessageType.INITIALIZE_MODULE_READER_REQUEST:
return try self.decoder.decode(as: InitializeModuleReaderRequest.self)
case MessageType.INITIALIZE_RESOURCE_READER_REQUEST:
return try self.decoder.decode(as: InitializeResourceReaderRequest.self)
case MessageType.CLOSE_EXTERNAL_PROCESS:
return try self.decoder.decode(as: CloseExternalProcess.self)
default:
fatalError("Unreachable code")
return try super.decodeMessage(messageType)
}
}
func getMessages() throws -> AsyncThrowingStream<ServerMessage, Error> {
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()
}
}
override func close() {
self._running = false
}
}

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 {
@ -26,6 +26,28 @@ public struct PklEvaluatorSettings: Decodable, Hashable {
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.
@ -85,3 +107,8 @@ public struct Proxy: Codable, Hashable {
/// ```
var noProxy: [String]?
}
public struct ExternalReader: Codable, Hashable {
var executable: String
var arguments: [String]? = nil
}

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 `pkl.Project`
public struct Project: PklRegisteredType, Hashable, DependencyDeclaredInProjectFile {

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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
@ -35,8 +35,8 @@ public protocol BaseReader {
/// birds:catalog/swallow.pkl
/// ```
///
/// The first URI conveys name "fred.pkl" within parent "/persons/". The second URI
/// conveys the name "persons/fred.pkl" with no hierarchical meaning.
/// The first URI conveys name "swallow.pkl" within parent "/catalog/". The second URI
/// conveys the name "catalog/swallow.pkl" with no hierarchical meaning.
var hasHierarchicalUris: Bool { get }
/// Returns elements at a specified path.
@ -107,6 +107,11 @@ public struct PathElement {
/// Whether the element is a directory or not.
public let isDirectory: Bool
public init(name: String, isDirectory: Bool) {
self.name = name
self.isDirectory = isDirectory
}
}
extension PathElement {

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 MessagePack
import PklSwiftInternals

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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
@ -85,3 +85,12 @@ public func resolvePaths(_ paths: String...) -> String {
}
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 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
//

View File

@ -1,12 +1,18 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
//
/*
* 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.
*/
#include "Discovery.h"

View File

@ -1,12 +1,18 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
//
/*
* 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.
*/
#if !defined(PKLS_DEFINES_H)
#define PKLS_DEFINES_H

View File

@ -1,12 +1,18 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
//
/*
* 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.
*/
#if !defined(PKLS_DISCOVERY_H)
#define PKLS_DISCOVERY_H

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 ArgumentParser
import Foundation
@ -77,11 +77,6 @@ struct PklGenSwift: AsyncParsableCommand {
)
var pklInputModules: [String] = []
func tempFile() -> URL {
let fileName = ProcessInfo.processInfo.globallyUniqueString + ".pkl"
return URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
}
private func generateScriptUrl() -> String {
if let generateScript = self.generateScript {
return URL(fileURLWithPath: generateScript).path

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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
@ -41,11 +41,6 @@ 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 {
let out = resolvePaths(self.settings.outputPath ?? ".out")
let moduleToEvaluate = """
@ -55,7 +50,7 @@ public struct PklSwiftGenerator {
moduleToGenerate = theModule
"""
let tempFile = tempFile()
let tempFile = try tempFile(suffix: ".pkl")
try moduleToEvaluate.write(to: tempFile, atomically: true, encoding: .utf8)
let files = try await evaluator.evaluateOutputFiles(source: .url(tempFile))
for (filename, contents) in files {

View File

@ -0,0 +1,51 @@
//===----------------------------------------------------------------------===//
// 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 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 XCTest

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 XCTest

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 XCTest

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 PklSwift
import XCTest

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 XCTest
@ -43,6 +43,11 @@ final class PklDecoderTests: XCTestCase {
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 {
let bytes: [UInt8] = [
0xD9, 0x27, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6B, 0x20, 0x66, 0x6F, 0x78,

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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

View File

@ -1,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
@testable import MessagePack
@testable import PklSwift
@ -305,10 +305,10 @@ final class PklSwiftTests: XCTestCase {
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 {
// let project1Dir = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("project1")
// let project1Dir = (try tempDir()).appendingPathComponent("project1")
// try FileManager.default.createDirectory(at: project1Dir, withIntermediateDirectories: true)
// try """
// amends "pkl:Project"

View File

@ -0,0 +1,65 @@
//===----------------------------------------------------------------------===//
// 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

@ -7,6 +7,9 @@ public protocol UnionTypes_Animal: PklRegisteredType, DynamicallyEquatable, Hash
var name: String { get }
}
public protocol UnionTypes_Shape: PklRegisteredType, DynamicallyEquatable, Hashable {
}
extension UnionTypes {
public enum Fruit: Decodable, Hashable {
case banana(Banana)
@ -14,8 +17,9 @@ extension UnionTypes {
case apple(Apple)
public init(from decoder: Decoder) throws {
let decoded = try decoder.singleValueContainer().decode(PklSwift.PklAny.self).value
switch decoded {
let container = try decoder.singleValueContainer()
let value = try container.decode(PklSwift.PklAny.self).value
switch value?.base {
case let decoded as Banana:
self = Fruit.banana(decoded)
case let decoded as Grape:
@ -27,14 +31,14 @@ extension UnionTypes {
Fruit.self,
.init(
codingPath: decoder.codingPath,
debugDescription: "Expected type Fruit, but got \(String(describing: decoded))"
debugDescription: "Expected type Fruit, but got \(String(describing: value))"
)
)
}
}
}
public enum City: String, CaseIterable, Decodable, Hashable {
public enum City: String, CaseIterable, CodingKeyRepresentable, Decodable, Hashable {
case sanFrancisco = "San Francisco"
case tokyo = "Tokyo"
case zurich = "Zurich"
@ -46,8 +50,9 @@ extension UnionTypes {
case donkey(Donkey)
public init(from decoder: Decoder) throws {
let decoded = try decoder.singleValueContainer().decode(PklSwift.PklAny.self).value
switch decoded {
let container = try decoder.singleValueContainer()
let value = try container.decode(PklSwift.PklAny.self).value
switch value?.base {
case let decoded as Zebra:
self = ZebraOrDonkey.zebra(decoded)
case let decoded as Donkey:
@ -57,7 +62,7 @@ extension UnionTypes {
ZebraOrDonkey.self,
.init(
codingPath: decoder.codingPath,
debugDescription: "Expected type ZebraOrDonkey, but got \(String(describing: decoded))"
debugDescription: "Expected type ZebraOrDonkey, but got \(String(describing: value))"
)
)
}
@ -80,8 +85,9 @@ extension UnionTypes {
}
public init(from decoder: Decoder) throws {
let decoded = try decoder.singleValueContainer().decode(PklSwift.PklAny.self).value
switch decoded {
let container = try decoder.singleValueContainer()
let value = try container.decode(PklSwift.PklAny.self).value
switch value?.base {
case let decoded as any Animal:
self = AnimalOrString.animal(decoded)
case let decoded as String:
@ -91,7 +97,7 @@ extension UnionTypes {
AnimalOrString.self,
.init(
codingPath: decoder.codingPath,
debugDescription: "Expected type AnimalOrString, but got \(String(describing: decoded))"
debugDescription: "Expected type AnimalOrString, but got \(String(describing: value))"
)
)
}
@ -107,6 +113,114 @@ 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 static let registeredIdentifier: String = "UnionTypes"
@ -132,6 +246,26 @@ extension UnionTypes {
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(
fruit1: Fruit,
fruit2: Fruit,
@ -143,7 +277,17 @@ extension UnionTypes {
animal1: ZebraOrDonkey,
animal2: ZebraOrDonkey,
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.fruit2 = fruit2
@ -156,6 +300,16 @@ extension UnionTypes {
self.animal2 = animal2
self.animalOrString1 = animalOrString1
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
}
}
@ -191,6 +345,18 @@ extension UnionTypes {
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 static let registeredIdentifier: String = "UnionTypes#Zebra"

View File

@ -1,3 +1,5 @@
import "pkl:math"
class Banana {
isRipe: Boolean
}
@ -18,6 +20,12 @@ typealias Fruit = Banana | Grape | Apple
typealias City = "San Francisco"|"Tokyo"|"Zurich"|"London"
abstract class Shape
class Square extends Shape {
fixed corners: Int = 4
}
fruit1: Fruit = new Banana {
isRipe = true
}
@ -52,4 +60,34 @@ typealias AnimalOrString = Animal|String
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 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 PklSwift
import XCTest
@ -160,7 +160,17 @@ class FixturesTest: XCTestCase {
animal1: .zebra(UnionTypes.Zebra(name: "Zebra")),
animal2: .donkey(UnionTypes.Donkey(name: "Donkey")),
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,18 +1,18 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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
@ -22,12 +22,13 @@ import XCTest
class ProjectTest: XCTestCase {
func testLoadProject() async throws {
let version = try await SemanticVersion(EvaluatorManager().getVersion())!
let tempDir = NSTemporaryDirectory()
try FileManager.default.createDirectory(atPath: tempDir + "/subdir", withIntermediateDirectories: true)
let otherProjectFile = URL(fileURLWithPath: tempDir, isDirectory: true)
.appendingPathComponent("subdir/PklProject")
let tempDir = try tempDir()
let subDir = tempDir.appendingPathComponent("subdir")
try FileManager.default.createDirectory(at: subDir, withIntermediateDirectories: true)
let otherProjectFile = subDir.appendingPathComponent("PklProject")
try #"""
@ModuleInfo { minPklVersion = "0.25.0" }
amends "pkl:Project"
package {
@ -38,8 +39,8 @@ class ProjectTest: XCTestCase {
}
"""#.write(to: otherProjectFile, atomically: true, encoding: .utf8)
let file = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
.appendingPathComponent("PklProject")
let file = try (PklSwift.tempDir()).appendingPathComponent("PklProject")
let httpSetting = version < pklVersion0_26 ? "" : """
http {
proxy {
@ -51,10 +52,40 @@ class ProjectTest: XCTestCase {
}
}
"""
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 #"""
amends "pkl:Project"
@ -99,7 +130,9 @@ class ProjectTest: XCTestCase {
timeout = 5.min
moduleCacheDir = "/bar/buzz"
rootDir = "/buzzy"
\#(externalReaderSettings)
\#(httpSetting)
\#(colorSetting)
}
dependencies {
@ -124,7 +157,10 @@ class ProjectTest: XCTestCase {
timeout: .minutes(5),
moduleCacheDir: "/bar/buzz",
rootDir: "/buzzy",
http: httpExpectation
http: httpExpectation,
externalModuleReaders: externalModuleReadersExpectation,
externalResourceReaders: externalResourceReadersExpectation,
color: color
)
let expectedPackage = PklSwift.Project.Package(
name: "hawk",
@ -179,7 +215,10 @@ class ProjectTest: XCTestCase {
timeout: nil,
moduleCacheDir: nil,
rootDir: nil,
http: nil
http: nil,
externalModuleReaders: nil,
externalResourceReaders: nil,
color: nil
),
projectFileUri: "\(otherProjectFile)",
tests: [],

View File

@ -1 +1 @@
0.3.0
0.4.2

View File

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

View File

@ -4,7 +4,7 @@ import PklSwift
public enum ExplicitlyCoolName {}
extension ExplicitlyCoolName {
public enum ConfigType: String, CaseIterable, Decodable, Hashable {
public enum ConfigType: String, CaseIterable, CodingKeyRepresentable, Decodable, Hashable {
case one = "one"
case two = "two"
}

View File

@ -4,7 +4,7 @@ import PklSwift
public enum UnionNameKeyword {}
extension UnionNameKeyword {
public enum `Type`: String, CaseIterable, Decodable, Hashable {
public enum `Type`: String, CaseIterable, CodingKeyRepresentable, Decodable, Hashable {
case one = "one"
case two = "two"
case three = "three"

View File

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

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
/// Generates Swift sources from Pkl
@swift.Module { name = "pkl_gen_swift" }
@ModuleInfo { minPklVersion = "0.24.0" }

View File

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

View File

@ -1,3 +1,19 @@
//===----------------------------------------------------------------------===//
// 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"
package {

View File

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

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
@Unlisted
module pkl.swift.internal.ClassGen

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
@Unlisted
module pkl.swift.internal.EnumGen
@ -57,6 +58,10 @@ local enumNormalMembers = enumBaseMembers.map((it) -> (it) {
else baseName
})
local enumNonNumericMembers = enumNormalMembers.filter((it) -> !it.type.isNumeric)
local enumNumericMembers = enumNormalMembers.filter((it) -> it.type.isNumeric)
contents =
if (isStringLiteralUnion) stringLiteralEnumContents
else enumContents
@ -66,7 +71,7 @@ local stringLiteralEnumContents =
when (alias.docComment != null) {
utils.renderDocComment(alias.docComment!!, "")
}
"public enum \(module.mapping.name): String, CaseIterable, Decodable, Hashable {"
"public enum \(module.mapping.name): String, CaseIterable, CodingKeyRepresentable, Decodable, Hashable {"
for (member in enumStringLiteralMembers) {
"\(module.indent)case \(member.name) = \(utils.toSwiftString((member.pklType as reflect.StringLiteralType).value))"
}
@ -79,33 +84,19 @@ local enumContents =
utils.renderDocComment(alias.docComment!!, "")
}
"public enum \(module.mapping.name): Decodable, Hashable {"
for (member in enumNormalMembers) {
for (member: EnumMember in enumNormalMembers) {
"\(module.indent)case \(member.name)(\(member.renderedType))"
}
""
when (!enumNumericMembers.isEmpty) {
decodeNumeric
""
}
when (enumNormalMembers.any((it) -> it.type.isPolymorphic)) {
synthesizedEquals
""
}
"\(module.indent)public init(from decoder: Decoder) throws {"
"\(module.indent.repeat(2))let decoded = try decoder.singleValueContainer().decode(PklSwift.PklAny.self).value"
"\(module.indent.repeat(2))switch decoded {"
for (member in enumNormalMembers) {
"\(module.indent.repeat(2))case let decoded as \(member.renderedType):"
"\(module.indent.repeat(3))self = \(module.mapping.name).\(member.name)(decoded)"
}
"""
\(module.indent.repeat(2))default:
\(module.indent.repeat(3))throw DecodingError.typeMismatch(
\(module.indent.repeat(4))\(module.mapping.name).self,
\(module.indent.repeat(4)).init(
\(module.indent.repeat(5))codingPath: decoder.codingPath,
\(module.indent.repeat(5))debugDescription: "Expected type \(module.mapping.name), but got \\(String(describing: decoded))"
\(module.indent.repeat(4)))
\(module.indent.repeat(3)))
\(module.indent.repeat(2))}
\(module.indent)}
"""
initMethod
when (enumNormalMembers.any((it) -> it.type.isPolymorphic)) {
""
synthesizedHash
@ -113,6 +104,44 @@ local enumContents =
"}"
}.join("\n")
local throwTypeMismatch = new Listing {
"\(module.indent.repeat(2))throw DecodingError.typeMismatch("
"\(module.indent.repeat(3))\(module.mapping.name).self,"
"\(module.indent.repeat(3)).init("
"\(module.indent.repeat(4))codingPath: decoder.codingPath,"
"\(module.indent.repeat(4))debugDescription: \"Expected type \(module.mapping.name), but got \\(String(describing: value))\""
"\(module.indent.repeat(3)))"
"\(module.indent.repeat(2)))"
}.join("\n")
local initMethod = new Listing {
"\(module.indent)public init(from decoder: Decoder) throws {"
"\(module.indent.repeat(2))let container = try decoder.singleValueContainer()"
when (!enumNumericMembers.isEmpty) {
"\(module.indent.repeat(2))let decoded = \(module.mapping.name).decodeNumeric(from: decoder, container)"
"\(module.indent.repeat(2))if decoded != nil {"
"\(module.indent.repeat(3))self = decoded!"
"\(module.indent.repeat(3))return"
"\(module.indent.repeat(2))}"
}
"\(module.indent.repeat(2))let value = try container.decode(PklSwift.PklAny.self).value"
when (!enumNonNumericMembers.isEmpty) {
"\(module.indent.repeat(2))switch value?.base {"
for (member in enumNonNumericMembers) {
"\(module.indent.repeat(2))case let decoded as \(member.renderedType):"
"\(module.indent.repeat(3))self = \(module.mapping.name).\(member.name)(decoded)"
}
"\(module.indent.repeat(2))default:"
// indent one more level
module.indent + throwTypeMismatch.split("\n").join("\n" + module.indent)
"\(module.indent.repeat(2))}"
} else {
throwTypeMismatch
}
"\(module.indent)}"
}
.join("\n")
local synthesizedEquals = new Listing {
"\(module.indent)public static func ==(lhs: \(module.mapping.name), rhs: \(module.mapping.name)) -> Bool {"
"\(module.indent.repeat(2))switch (lhs, rhs) {"
@ -141,6 +170,23 @@ local synthesizedHash = new Listing {
"\(module.indent)}"
}.join("\n")
local decodeNumeric = new Listing {
"\(module.indent)private static func decodeNumeric(from decoder: Decoder, _ container: any SingleValueDecodingContainer) -> \(module.mapping.name)? {"
when (enumNumericMembers.length == 1) {
local member = enumNumericMembers.first
"\(module.indent.repeat(2))return try? .\(member.name)(container.decode(\(member.renderedType).self))"
} else {
for (idx, member in enumNumericMembers) {
when (idx == 0) {
"\(module.indent.repeat(2))return (try? .\(member.name)(container.decode(\(member.renderedType).self)))"
} else {
"\(module.indent.repeat(3))?? (try? .\(member.name)(container.decode(\(member.renderedType).self)))"
}
}
}
"\(module.indent)}"
}.join("\n")
local class EnumMember {
name: String
type: Type

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
@Unlisted
abstract module pkl.swift.internal.Gen

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
@Unlisted
abstract module pkl.swift.internal.SwiftMapping

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
@Unlisted
module pkl.swift.internal.SwiftNamespace

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
/// Representation of a type in Swift.
@Unlisted
abstract module pkl.swift.internal.Type
@ -28,6 +29,9 @@ isPolymorphic: Boolean = false
/// True if this type represents a Pkl Any
isAny: Boolean = false
/// Tells if this type represents a number (int or float) or not
isNumeric: Boolean = false
/// Renders this type into source code.
///
/// [swiftModuleName] is the full path of the package that this type appears in.

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
@Unlisted
module pkl.swift.internal.TypeAliasGen

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
@Unlisted
module pkl.swift.internal.gatherer

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
/// Utilities for generating Swift types from Pkl.
@Unlisted
module pkl.swift.internal.typegen
@ -76,16 +77,16 @@ anyType: Type.Nullable = new { elem = builtInType("AnyHashable") }
local neverType: Type.Declared = builtInType("Never")
mappedTypes: Mapping<Class|TypeAlias, Type> = new {
[Int] = new Type.Declared { typeName = "Int" }
[Int8] = new Type.Declared { typeName = "Int8" }
[Int16] = new Type.Declared { typeName = "Int16" }
[Int32] = new Type.Declared { typeName = "Int32" }
[UInt] = new Type.Declared { typeName = "UInt" }
[UInt8] = new Type.Declared { typeName = "UInt8" }
[UInt16] = new Type.Declared { typeName = "UInt16" }
[UInt32] = new Type.Declared { typeName = "UInt32" }
[Number] = new Type.Declared { typeName = "Float64" }
[Float] = new Type.Declared { typeName = "Float64" }
[Int] = new Type.Declared { typeName = "Int"; isNumeric = true }
[Int8] = new Type.Declared { typeName = "Int8"; isNumeric = true }
[Int16] = new Type.Declared { typeName = "Int16"; isNumeric = true }
[Int32] = new Type.Declared { typeName = "Int32"; isNumeric = true }
[UInt] = new Type.Declared { typeName = "UInt"; isNumeric = true }
[UInt8] = new Type.Declared { typeName = "UInt8"; isNumeric = true }
[UInt16] = new Type.Declared { typeName = "UInt16"; isNumeric = true }
[UInt32] = new Type.Declared { typeName = "UInt32"; isNumeric = true }
[Number] = new Type.Declared { typeName = "Float64"; isNumeric = true }
[Float] = new Type.Declared { typeName = "Float64"; isNumeric = true }
[String] = new Type.Declared { typeName = "String" }
[Boolean] = new Type.Declared { typeName = "Bool" }
[Null] = new Type.Declared { typeName = "Optional"; typeArguments = List(neverType) }

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
@Unlisted
module pkl.swift.internal.utils

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
@Module { name = "pkl_gen_swift" }
module pkl.swift.swift

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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:test"
import ".../internal/ClassGen.pkl"

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
class Bike {
isFixie: Boolean
}

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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 "types3.pkl"
class Person {

View File

@ -1,16 +1,17 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
class Bike

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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.
// ===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
class Foo {
bar: Listing<Int|String>
}

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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:test"
import "pkl:reflect"

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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:test"
import "pkl:reflect"

View File

@ -1,18 +1,19 @@
// ===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//===----------------------------------------------------------------------===//
// 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
// 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:test"
import "../internal/utils.pkl"

View File

@ -1,5 +1,5 @@
name: swift
title: Pkl Swift Bindings
version: 0.3.0
version: 0.4.2
nav:
- nav.adoc

View File

@ -1,5 +1,46 @@
= Changelog
[[release-0.4.2]]
== 0.4.2 (2025-04-14)
=== Fixes
* Fixes an issue where enum keys fail to be decoded (https://github.com/apple/pkl-swift/pull/45[#45]).
* Fixes an issue where unions of ints can possibly be decoded incorrectly (https://github.com/apple/pkl-swift/pull/47[#47]).
=== Miscellaneous
* Auto-generate DocC documentation in the Swift Package Index (https://github.com/apple/pkl-swift/pull/41[#41]).
* Update license headers (https://github.com/apple/pkl-swift/pull/43[#43]).
[[release-0.4.1]]
== 0.4.1 (2025-02-04)
=== Fixes
* Fixes an issue where union types might get decoded as the wrong Swift type (https://github.com/apple/pkl-swift/pull/39[#39]).
[[release-0.4.0]]
== 0.4.0 (2025-01-24)
=== Additions
* Add a new API for creating external readers, called `ExternalReaderClient` (https://github.com/apple/pkl-swift/pull/26[#26]).
* Add new fields to support new options available in Pkl 0.27 (https://github.com/apple/pkl-swift/pull/26[#26], https://github.com/apple/pkl-swift/pull/32[#32]):
- In struct `EvaluatorOptions`: `externalModuleReaders` and `externalResourceReaders`.
- In struct `PklEvaluatorSettings`: `externalModuleReaders`, `externalResourceReaders`, and `color`.
=== Changes
* Make `PathElement.init` public (https://github.com/apple/pkl-swift/pull/31[#31]).
=== Contributors ❤️
Thank you to all our contributors!
* https://github.com/HT154[@HT154]
* https://github.com/jcubit[@jcubit]
[[release-0.3.0]]
== 0.3.0 (2024-10-10)

View File

@ -0,0 +1,37 @@
= External Readers
pkl-swift provides APIs that aid in implementing xref:main:language-reference:index.adoc#external-readers[External Readers].
In this mode of execution, the program built with pkl-swift runs as a child process of the Pkl evaluator, rather than a parent process.
The `PklSwift.ExternalReaderClient` type provides a set of tools for building external readers.
Much like implementing xref:ROOT:evaluation.adoc#custom-readers[Custom Readers], external readers are implemented by providing one or more instances of the `PklSwift.ResourceReader` and `pkl.ModuleReader` protocols.
== Example
.main.swift
[source,swift]
----
import Foundation
import PklSwift
@main struct Main {
static func main() async throws {
let client = ExternalReaderClient(
options: ExternalReaderClientOptions(
resourceReaders: [MyResourceReader()]
))
try await client.run()
}
}
struct MyResourceReader: ResourceReader {
var scheme: String { "env2" }
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(scheme.count + 1)
return Array((ProcessInfo.processInfo.environment[String(key)] ?? "").utf8)
}
}
----

View File

@ -1,4 +1,5 @@
* xref:ROOT:quickstart.adoc[Quickstart]
* xref:ROOT:evaluation.adoc[Evaluator API]
* xref:ROOT:codegen.adoc[Code Generation]
* xref:ROOT:external-readers.adoc[External Readers]
* xref:ROOT:CHANGELOG.adoc[Changelog]

View File

@ -1,3 +1,19 @@
//===----------------------------------------------------------------------===//
// 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 "codegen/src/GeneratorSettings.pkl"
generateScript = "codegen/src/Generator.pkl"

29
licenserc.toml Normal file
View File

@ -0,0 +1,29 @@
additionalHeaders = ["scripts/pkl-header-style.toml"]
headerPath = "scripts/license-header.txt"
includes = [
"*.swift",
"*.pkl",
"*.h",
"*.cpp",
"*.sh",
"PklProject",
]
excludes = [
"Sources/pkl-gen-swift/Generated",
"Tests/PklSwiftTests/Fixtures",
"codegen/snippet-tests",
"doc",
]
[git]
attrs = 'enable'
ignore = 'enable'
[properties]
copyrightOwner = "Apple Inc. and the Pkl project authors"
[mapping.SWIFT_STYLE]
extensions = ["swift"]

View File

@ -0,0 +1,13 @@
Copyright ©{{ " " }}{%- if attrs.git_file_modified_year != attrs.git_file_created_year -%}{{ attrs.git_file_created_year }}-{{ attrs.git_file_modified_year }}{%- else -%}{{ attrs.git_file_created_year }}{%- endif -%}{{ " " }}{{ props["copyrightOwner"] }}. 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.

View File

@ -0,0 +1,11 @@
[SWIFT_STYLE]
firstLine = '//===----------------------------------------------------------------------===//'
endLine = "//===----------------------------------------------------------------------===//\n"
beforeEachLine = '// '
afterEachLine = ''
allowBlankLines = false
multipleLines = true
padLines = false
firstLineDetectionPattern = '//\s?==='
lastLineDetectionPattern = '//\s?==='
skipLinePattern = '// swift-tools-version'

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