pkl Documentation

A configuration as code language with rich validation and tooling.

11,454 stars Java Java 1 file ยท ~6,385 tokens #config#configuration#data#functional#java#json#kotlin#language
RAW Doc

File: docs/modules/style-guide/pages/index.adoc

= Pkl Style Guide
:icons: font
:source-highlighter: highlight.js
:pkl-expr: pkl expression
:pkl: pkl
:sectnums:

This document serves as the Pkl team's recommended coding standard for the Pkl configuration language.

== Files

=== Filename

Use the .pkl extension for all files.

Follow these rules for casing the file's name:

[cols="1,3,1"]
|===
| Casing | Description | Example
| PascalCase
| It is designed to be used as a template, or used as a class (i.e. imported and instantiated).
| K8sResource.pkl
| camelCase
| It is designed to be used as a value.
| myDeployment.pkl
| kebab-case
| It is designed to be used as a CLI tool.
| do-convert.pkl
|===

Exception: If a file is meant to render into a static configuration file, the filename should match the target file's name without the extension.
For example, config.pkl turns into config.yml.

Exception: The PklProject file cannot have any extension.

=== File Encoding

Encode all files using UTF-8.

== Module Structure

=== Header

Separate each section of the module header by one blank line.

A module header consists of the following clauses, each of which is optional:

  • Module clause
  • amends or extends clause
  • Import clauses

.module.pkl [source%parsed,{pkl}]

module com.example.Foo // <1>

extends "Bar.pkl" // <2>

import "baz.pkl" // <3> import "Buz.pkl" // <3>

<1> Module clause
<2> extends clause
<3> Import clause

==== Module name

Match the name of the module with the name of the file.

.MyModule.pkl [source%tested,{pkl}]

module MyModule


If a module is meant to be published, add a module clause, @ModuleInfo annotation, and doc comments.

Modules that do not get published anywhere may omit a module clause.

.MyModule.pkl [source%tested,{pkl}]

/// Used for some type of purpose. <1>
@ModuleInfo { minPklVersion = "0.24.0" } // <2>
module MyModule // <3>


<1> Doc comments
<2> @ModuleInfo annotation
<3> Module clause

==== amends vs. extends clause

A module that doesn't add new properties shouldn't use the extends clause.

==== Imports

Sort imports sections using https://en.wikipedia.org/wiki/Natural_sort_order[natural sorting] by their module URI.
Relative path and package imports should be in their own section, separated by a newline.
There should be no unused imports.

[source%parsed,{pkl}]

import "modulepath:/foo.pkl"
import "package://example.com/[email protected]#/foo.pkl"

import "@mypackage/baz.pkl"

import ".../my/file/bar2.pkl" import ".../my/file/bar11.pkl"

=== Module body

Within a module body, define members in this order:

  1. Properties
  2. Methods
  3. Classes and type aliases
  4. The amended xref:language-reference:index.adoc#in-language[output] property.

Exception: local members can be close to their usage.

Exception: functions meant to be a class constructor can be next to the class declaration.

.constructor.pkl [source%tested,{pkl}]

function MyClass(_name: String): MyClass = new { name = _name }

class MyClass { name: String }

=== Module URIs

If possible, use xref:language-reference:index.adoc#triple-dot-module-uris[triple-dot Module URIs] to reference ancestor modules
instead of multiple ../.

.good.pkl [source%parsed,{pkl}]

amends ".../ancestor.pkl"

import ".../ancestor2.pkl"

.bad.pkl [source%parsed,{pkl}]

amends "../../../ancestor.pkl"

import "../../../ancestor2.pkl"

== Objects

=== Member spacing

Object members (properties, elements, and entries) should be separated by at most one blank line.

.good.pkl [source%tested,{pkl}]

foo = "bar"

baz = "buz"

.good.pkl [source%tested,{pkl}]

foo = "bar" baz = "buz"

.bad.pkl [source%tested,{pkl}]

foo = "bar"

baz = "buz"

Too many lines separate foo and baz.

=== Overridden properties

Properties that override an existing property shouldn't have doc comments nor type annotations,
unless the type is intentionally overridden via extends.

[source%parsed,{pkl}]

amends "myOtherModule.pkl"

foo = "bar"

=== New property definitions

Each property definition should have a type annotation and <<doc-comment,doc comment>>.
Successive definitions should be separated by a blank line.

.good.pkl [source%parsed,{pkl}]

/// Denotes something.
myFoo: String

/// Something else myOtherFoo: String

.bad.pkl [source%parsed,{pkl}]

/// Denotes something. myFoo: String /// Something else myOtherFoo: String

=== Objects with new

When initializing a Typed object using new, omit the type.
For example, use new {} instead of new Foo {}.

This rule does not apply when initializing a property to a subtype of the property's declared type.

.good.pkl [source%parsed,{pkl}]

myFoo: Foo = new { foo = "bar" }

.good.pkl [source%parsed,{pkl}]

open class Foo {}
class Bar extends Foo {}

foo: Foo = new Bar {}

This is okay because this is meaning to initialize Bar instead of Foo.

.bad.pkl [source%parsed,{pkl}]

myFoo1: Foo = new Foo { foo = "bar" } // <1>

myFoo2 = new Foo { foo = "bar" } // <2>

<1> Unnecessary new Foo { ... }
<2> Unless amending/extending a module where myFoo2 is already defined, myFoo2 is effectively the unknown type, i.e. myFoo2: unknown.

== Comments

Use doc comments to convey information to users of a module.
Use line comments or block comments to convey implementation concerns to authors of a module, or to comment out code.

[[doc-comment]]
=== Doc comments

Doc comments should start with a one sentence summary paragraph, followed by additional paragraphs if necessary.
Start new sentences on their own line.

[source%parsed,{pkl}]

/// The time allotted for eating lunch. /// /// Note: /// * Hamburgers typically take longer to eat than salad. /// * Pizza gets prepared per-order. /// /// Orders must be placed on-prem. /// See for more details. lunchHours: Duration

=== Line comments

If a comment relates to a property definition, place it after the property's doc comments.
Add a single space after //.

.good.pkl [source%parsed,{pkl}]

/// Designates whether it is zebra party time. // TODO: Add constraints here? partyTime: Boolean

A line comment may also be placed at the end of a line, as long as the line doesn't exceed 100 characters.

.good.pkl [source%tested,{pkl}]

/// Designates whether it is zebra party time. partyTime: Boolean // TODO: Add constraints here?

=== Block comments

A single-line block comment should have a single space after +++/*+++ and before +++*/+++.

.good.pkl [source%tested,{pkl}]

/* Let's have a zebra party */

.bad.pkl [source%tested,{pkl}]

/*Let's have a zebra party*/

== Classes

=== Class names

Name classes in PascalCase.

.good.pkl [source%tested,{pkl}]

class ZebraParty {}

.bad.pkl [source%tested,{pkl}]

class zebraParty {}

== Strings

=== Custom String Delimiters

Use xref:language-reference:index.adoc#custom-string-delimiters[custom string delimiters] to avoid the need for string escaping.

.good.pkl [source%tested,{pkl}]

myString = #"foo \ bar \ baz"#

.bad.pkl [source%tested,{pkl}]

myString = "foo \\ bar \\ baz"

NOTE: Sometimes, using custom string delimiters makes source code harder to read. For example, the +\#+ literal reads better using escapes ("\\#") than using custom string delimiters (+##"\#"##+).

=== Interpolation

Prefer interpolation to string concatenation.

.good.pkl [source%parsed,{pkl}]

greeting = "Hello, \(name)"

.bad.pkl [source%parsed,{pkl}]

greeting = "Hello, " + name

== Formatting

=== Line width

Lines shouldn't exceed 100 characters.

Exceptions:

  1. String literals
  2. Code snippets within doc comments

=== Indentation

Use two spaces per indentation level.

==== Members within braces

Members within braces should be indented one level deeper than their parents.

[source%tested,{pkl}]

foo {
bar {
baz = "hi"
}

}

==== Assignment operator (=)

An assignee that starts after a newline should be indented.

.good.pkl [source%tested,{pkl}]

foo =
"foo"

bar =
new {
baz = "baz"
biz = "biz"

}

.bad.pkl [source%tested,{pkl}]

foo =
"foo"

bar = new { baz = "baz" biz = "biz" }

An assignee that starts on the same line should not be indented.

.good.pkl [source%tested,{pkl}]

foo = new { baz = "baz" biz = "biz" }

.bad.pkl [source%tested,{pkl}]

foo = new {
baz = "baz"
biz = "biz"

}

==== if and let expressions

if and let bodies that start on their own line should be indented.
Child bodies may also be inline, and the else branch of if expressions may be inline of if.

.good.pkl [source%parsed,{pkl-expr}]

if (bar) bar else foo

.good.pkl [source%parsed,{pkl-expr}]

if (bar) bar else foo

.good.pkl [source%parsed,{pkl-expr}]

let (foo = "bar") foo.toUpperCase()

.good.pkl [source%parsed,{pkl-expr}]

let (foo = "bar") foo.toUpperCase()

.bad.pkl [source%parsed,{pkl-expr}]

if (bar) bar else foo

.bad.pkl [source%parsed,{pkl-expr}]

let (foo = "bar") foo.toUpperCase()

Exception: A nested if expression within the else branch should have the same indentation level as its parent, and start on the same line as the parent else keyword.

.good.pkl [source%parsed,{pkl-expr}]

if (bar) bar else if (baz) baz else foo

.bad.pkl [source%parsed,{pkl-expr}]

if (bar)
bar
else
if (baz)
baz
else
foo


==== Multiline chained method calls

Indent successive multiline chained method calls.

[source%parsed,{pkl-expr}]

foo() .bar() .baz() .biz()

==== Multiline binary operators

Place operators after the newline, and indent successive lines to the same level.

.good.pkl [source%parsed,{pkl}]

foo = bar
|> baz
|> biz

myNum = 1

  • 2
  • 3
  • 4

.bad.pkl [source%parsed,{pkl}]

foo = bar |>
baz |>
biz

myNum = 1 + 2 + 3 + 4

.bad.pkl [source%tested,{pkl}]

foo = bar |> baz |> biz

.bad.pkl [source%tested,{pkl}]

foo = bar
|> baz
|> biz


Exception: the minus operator must come before the newline, because otherwise it is parsed as a unary minus.

.good.pkl [source%tested,{pkl}]

myNum = 1 - 2 - 3 - 4

.bad.pkl [source%tested,{pkl}]

myNum = 1

  • 2
  • 3
  • 4

=== Spaces

Add a space:

[source%parsed,{pkl}]

amends "Foo.pkl" // <1>

res1 { "foo" } // <2>
res2 = 1 + 2 // <3>
res3 = res2 as Number // <3>
res4 = List(1, 2, 3) // <4>
res5 = if (foo) bar else baz // <5>

typealias Foo = "foo" | "bar" | "baz" // <6>

<1> After keywords
<2> Before and after braces
<3> Around infix operators
<4> After a comma
<5> Before opening parentheses in control operators (if, for, when are control operators)
<6> Before and after the pipe symbol (|)

=== Object bodies

==== Single line

An object body may be a single line if it only consists of primitive elements, or if it contains two or fewer members.
Otherwise, split them into multiple lines.

Separate each member of a single line object with a semicolon and a space.

.good.pkl [source%tested,{pkl}]

res1 = new { bar = "bar"; baz = "baz" } res2 = new { 1; 2; 3; 4; 5; 6 }

.bad.pkl [source%parsed,{pkl}]

res1 = new { bar = "bar"; baz = "baz"; biz = "biz"; } // <1>

res2 = new { 1 2 3 4 5 6 } // <2>

<1> Too many members and trailing ;
<2> No semicolon

==== Multiline

Multiline objects should have their members separated by at least one line break and at most one blank line.

.good.pkl [source%tested,{pkl}]

res {
foo = "foo"
bar = "bar"
}

res2 {
["foo"] = "foo"
["bar"] = "bar"
}

res3 { "foo" "bar" }

.good.pkl [source%tested,{pkl}]

res {
foo = "foo"

bar = "bar"
}

res2 {
["foo"] = "foo"

["bar"] = "bar"
}

res3 {
"foo"

"bar" }

.bad.pkl [source%tested,{pkl}]

res {
foo = "foo"

bar = "bar" // <1>
}

res2 {
["foo"] = "foo"

["bar"] = "bar" // <1>
}

res3 {
"foo"

"bar" // <1>
}

res4 { foo = "foo"; bar = "bar" // <2> }

<1> Too many blank lines between members
<2> No line break separating members

Put the opening brace on the same line.

.good.pkl

[source%tested,{pkl}]

res { foo = "foo" bar = "bar" }

.bad.pkl [source%tested,{pkl}]

res { foo = "foo" bar = "bar" }

== Programming Practices

=== Prefer for generators

When programmatically creating elements and entries, prefer
xref:language-reference:index.adoc#for-generators[for generators] over using the collection API.
Using for generators preserves xref:language-reference:index.adoc#late-binding[late binding].

.good.pkl [source%tested,{pkl}]

numbers {
1
2
3
4
}

squares {
for (num in numbers) {
num ** 2
}

}

.bad.pkl [source%tested,{pkl}]

numbers {
1
2
3
4
}

squares = numbers.toList().map((num) -> num ** 2).toListing()


File: docs/modules/ROOT/partials/component-attributes.adoc

// TODO: move to antora.yml once supported

// the following attributes must be updated immediately before a release

// pkl version corresponding to current git commit without -dev suffix or git hash
:pkl-version-no-suffix: 0.33.0
// tells whether pkl version corresponding to current git commit
// is a release version (:is-release-version: '') or dev version (:!is-release-version:)
:!is-release-version:

// the remaining attributes do not need to be updated regularly

:pkl-version: {pkl-version-no-suffix}-dev
ifdef::is-release-version[]
:pkl-version: {pkl-version-no-suffix}
endif::[]

// use non-unique snapshot version because we have no way to determine unique snapshot version here
:pkl-artifact-version: {pkl-version-no-suffix}-SNAPSHOT
ifdef::is-release-version[]
:pkl-artifact-version: {pkl-version}
endif::[]

:uri-maven-docsite: https://central.sonatype.com

:uri-snapshot-repo: https://central.sonatype.com/repository/maven-snapshots

:uri-maven-repo: https://central.sonatype.com/repository/maven-snapshots
ifdef::is-release-version[]
:uri-maven-repo: https://repo1.maven.org/maven2
endif::[]

:symbolic-version-name: latest
ifdef::is-release-version[]
:symbolic-version-name: current
endif::[]
:uri-pkl-docs-base: https://pkl-lang.org/package-docs
:uri-pkl-stdlib-docs-base: {uri-pkl-docs-base}/pkl
:uri-pkl-stdlib-docs: {uri-pkl-stdlib-docs-base}/{pkl-version}
:uri-pkl-stdlib-docs-index: {uri-pkl-stdlib-docs}/

:github-branch: main
ifdef::is-release-version[]
:github-branch: {pkl-version-no-suffix}
endif::[]
:uri-github-tree: https://github.com/apple/pkl/tree/{github-branch}
:uri-pkl-stdlib-sources: {uri-github-tree}/stdlib

:github-releases-base: https://github.com/apple/pkl/releases
:github-releases: {github-releases-base}/download/{pkl-artifact-version}

:uri-pkl-core-main-sources: {uri-github-tree}/pkl-core/src/main/java/org/pkl/core
:uri-pkl-cli-main-sources: {uri-github-tree}/pkl-cli/src/main/kotlin/org/pkl/cli
:uri-pkl-doc-main-sources: {uri-github-tree}/pkl-doc/src/main/kotlin/org/pkl/doc

// This attribute is used as language for Pkl code blocks.
// It can then be mapped to different languages in different environments (e.g., IntelliJ vs. Antora).
:pkl: pkl
:pkl-expr: pkl expression

:uri-pkl-examples-repo: https://github.com/apple/pkl-jvm-examples
:uri-pkl-examples-tree: {uri-pkl-examples-repo}/tree/main
:uri-build-eval-example: {uri-pkl-examples-tree}/build-eval
:uri-codegen-java-example: {uri-pkl-examples-tree}/codegen-java
:uri-codegen-kotlin-example: {uri-pkl-examples-tree}/codegen-kotlin
:uri-config-java-example: {uri-pkl-examples-tree}/config-java
:uri-config-kotlin-example: {uri-pkl-examples-tree}/config-kotlin
:uri-pkldoc-example: {uri-pkl-examples-tree}/pkldoc

:uri-stdlib-baseModule: {uri-pkl-stdlib-docs}/base
:uri-stdlib-CommandModule: {uri-pkl-stdlib-docs}/Command
:uri-stdlib-refModule: {uri-pkl-stdlib-docs}/ref
:uri-stdlib-analyzeModule: {uri-pkl-stdlib-docs}/analyze
:uri-stdlib-jsonnetModule: {uri-pkl-stdlib-docs}/jsonnet
:uri-stdlib-reflectModule: {uri-pkl-stdlib-docs}/reflect
:uri-stdlib-mathModule: {uri-pkl-stdlib-docs}/math
:uri-stdlib-xmlModule: {uri-pkl-stdlib-docs}/xml
:uri-stdlib-protobufModule: {uri-pkl-stdlib-docs}/protobuf
:uri-stdlib-pklbinaryModule: {uri-pkl-stdlib-docs}/pklbinary
:uri-stdlib-yamlModule: {uri-pkl-stdlib-docs}/yaml
:uri-stdlib-YamlParser: {uri-stdlib-yamlModule}/Parser
:uri-stdlib-projectModule: {uri-pkl-stdlib-docs}/Project
:uri-stdlib-evaluatorSettingsModule: {uri-pkl-stdlib-docs}/EvaluatorSettings
:uri-stdlib-evaluatorSettingsHttpClass: {uri-stdlib-evaluatorSettingsModule}/Http
:uri-stdlib-evaluatorSettingsExternalReaderClass: {uri-stdlib-evaluatorSettingsModule}/ExternalReader
:uri-stdlib-Boolean: {uri-stdlib-baseModule}/Boolean
:uri-stdlib-xor: {uri-stdlib-baseModule}/Boolean#xor()
:uri-stdlib-implies: {uri-stdlib-baseModule}/Boolean#implies()
:uri-stdlib-Any: {uri-stdlib-baseModule}/Any
:uri-stdlib-String: {uri-stdlib-baseModule}/String
:uri-stdlib-Collection: {uri-stdlib-baseModule}/Collection
:uri-stdlib-StringToInt: {uri-stdlib-baseModule}/String#toInt()
:uri-stdlib-Int: {uri-stdlib-baseModule}/Int
:uri-stdlib-Float: {uri-stdlib-baseModule}/Float
:uri-stdlib-Number: {uri-stdlib-baseModule}/Number
:uri-stdlib-NaN: {uri-stdlib-baseModule}/#NaN
:uri-stdlib-Infinity: {uri-stdlib-baseModule}/#Infinity
:uri-stdlib-isBetween: {uri-stdlib-baseModule}/Number#isBetween
:uri-stdlib-isFinite: {uri-stdlib-baseModule}/Number#isFinite
:uri-stdlib-Int8: {uri-stdlib-baseModule}/#Int8
:uri-stdlib-Int16: {uri-stdlib-baseModule}/#Int16
:uri-stdlib-Int32: {uri-stdlib-baseModule}/#Int32
:uri-stdlib-UInt8: {uri-stdlib-baseModule}/#UInt8
:uri-stdlib-UInt16: {uri-stdlib-baseModule}/#UInt16
:uri-stdlib-UInt32: {uri-stdlib-baseModule}/#UInt32
:uri-stdlib-UInt: {uri-stdlib-baseModule}/#UInt
:uri-stdlib-Uri: {uri-stdlib-baseModule}/#Uri
:uri-stdlib-matches: {uri-stdlib-baseModule}/String#matches()
:uri-stdlib-Null: {uri-stdlib-baseModule}/Null
:uri-stdlib-ifNonNull: {uri-stdlib-baseModule}/Null#ifNonNull()
:uri-stdlib-List: {uri-stdlib-baseModule}/List
:uri-stdlib-Set: {uri-stdlib-baseModule}/Set
:uri-stdlib-Map: {uri-stdlib-baseModule}/Map
:uri-stdlib-Listing: {uri-stdlib-baseModule}/Listing
:uri-stdlib-Listing-default: {uri-stdlib-baseModule}/Listing#default
:uri-stdlib-Listing-isDistinct: {uri-stdlib-baseModule}/Listing#isDistinct
:uri-stdlib-Listing-isDistinctBy: {uri-stdlib-baseModule}/Listing#isDistinctBy()
:uri-stdlib-Mapping: {uri-stdlib-baseModule}/Mapping
:uri-stdlib-Mapping-default: {uri-stdlib-baseModule}/Mapping#default
:uri-stdlib-Duration: {uri-stdlib-baseModule}/Duration
:uri-stdlib-Duration-value: {uri-stdlib-baseModule}/Duration#value
:uri-stdlib-Duration-unit: {uri-stdlib-baseModule}/Duration#unit
:uri-stdlib-DurationUnit: {uri-stdlib-baseModule}/#DurationUnit
:uri-stdlib-DataSize: {uri-stdlib-baseModule}/DataSize
:uri-stdlib-DataSize-value: {uri-stdlib-baseModule}/DataSize#value
:uri-stdlib-DataSize-unit: {uri-stdlib-baseModule}/DataSize#unit
:uri-stdlib-DataSizeUnit: {uri-stdlib-baseModule}/#DataSizeUnit
:uri-stdlib-Dynamic: {uri-stdlib-baseModule}/Dynamic
:uri-stdlib-Dynamic-toTyped: {uri-stdlib-baseModule}/Dynamic#toTyped()
:uri-stdlib-Typed: {uri-stdlib-baseModule}/Typed
:uri-stdlib-Regex: {uri-stdlib-baseModule}/Regex
:uri-stdlib-Regex-method: {uri-stdlib-baseModule}/#Regex()
:uri-stdlib-Regex-match: {uri-stdlib-baseModule}/Regex#match
:uri-stdlib-RegexMatch: {uri-stdlib-baseModule}/RegexMatch
:uri-stdlib-Pair: {uri-stdlib-baseModule}/Pair
:uri-stdlib-IntSeq: {uri-stdlib-baseModule}/IntSeq
:uri-stdlib-Class: {uri-stdlib-baseModule}/Class
:uri-stdlib-TypeAlias: {uri-stdlib-baseModule}/TypeAlias
:uri-stdlib-Deprecated: {uri-stdlib-baseModule}/Deprecated
:uri-stdlib-BaseValueRenderer: {uri-stdlib-baseModule}/BaseValueRenderer
:uri-stdlib-ValueRenderer: {uri-stdlib-baseModule}/ValueRenderer
:uri-stdlib-BytesRenderer: {uri-stdlib-baseModule}/BytesRenderer
:uri-stdlib-YamlRenderer: {uri-stdlib-baseModule}/YamlRenderer
:uri-stdlib-PcfRenderer-converters: {uri-stdlib-baseModule}/PcfRenderer#converters
:uri-stdlib-Function: {uri-stdlib-baseModule}/Function
:uri-stdlib-Function0: {uri-stdlib-baseModule}/Function0
:uri-stdlib-Function1: {uri-stdlib-baseModule}/Function1
:uri-stdlib-Function1-apply: {uri-stdlib-baseModule}/Function1#apply()
:uri-stdlib-Function2: {uri-stdlib-baseModule}/Function2
:uri-stdlib-Function3: {uri-stdlib-baseModule}/Function3
:uri-stdlib-Function4: {uri-stdlib-baseModule}/Function4
:uri-stdlib-Function5: {uri-stdlib-baseModule}/Function5
:uri-stdlib-Bytes: {uri-stdlib-baseModule}/Bytes
:uri-stdlib-Resource: {uri-stdlib-baseModule}/Resource
:uri-stdlib-outputFiles: {uri-stdlib-baseModule}/ModuleOutput#files
:uri-stdlib-FileOutput: {uri-stdlib-baseModule}/FileOutput
:uri-stdlib-Annotation: {uri-stdlib-baseModule}/Annotation
:uri-stdlib-ConvertProperty: {uri-stdlib-baseModule}/ConvertProperty
:uri-stdlib-Command-Flag: {uri-stdlib-CommandModule}/Flag
:uri-stdlib-Command-BooleanFlag: {uri-stdlib-CommandModule}/BooleanFlag
:uri-stdlib-Command-CountedFlag: {uri-stdlib-CommandModule}/CountedFlag
:uri-stdlib-Command-Argument: {uri-stdlib-CommandModule}/Argument
:uri-stdlib-Command-Import: {uri-stdlib-CommandModule}/Import
:uri-stdlib-ref-Reference: {uri-stdlib-baseModule}/Reference
:uri-stdlib-ref-Access: {uri-stdlib-baseModule}/Access

:uri-messagepack: https://msgpack.org/index.html
:uri-messagepack-spec: https://github.com/msgpack/msgpack/blob/master/spec.md

:uri-pkl-roadmap: https://github.com/orgs/apple/projects/12/views/1

// TODO: figure out what the correct URL should be
:uri-sonatype-snapshot-download: https://s01.oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=org.pkl-lang&v={pkl-artifact-version}


File: docs/modules/ROOT/pages/evolution-and-roadmap.adoc

= Evolution and Roadmap

:uri-pkl-roadmap: https://github.com/orgs/apple/projects/12/views/1
:uri-pkl-evolution: https://github.com/apple/pkl-evolution

== Evolution

Sometimes, a change to Pkl is large enough that it makes sense to create a proposal for the change so that it can be discussed in detail and vetted.

Pkl has a process for managing such designs in a repository called {uri-pkl-evolution}[Pkl Evolution].

== Roadmap

To discover what might be coming in future versions, reference the {uri-pkl-roadmap}[Pkl Roadmap] project on GitHub.

The roadmap describes estimates.
The Pkl team aims to cut a release in February, June, and October of each year.
If an item is not complete by the release cutoff date, the roadmap item may be bumped to the next release.

Additionally, as priorities change, it is possible that items can be moved around or backlogged.


File: docs/modules/ROOT/pages/examples.adoc

= Examples

:uri-github-apple: https://github.com/apple
:uri-jvm-examples: {uri-github-apple}/pkl-jvm-examples
:uri-go-examples: {uri-github-apple}/pkl-go-examples
:uri-swift-examples: {uri-github-apple}/pkl-swift-examples
:uri-k8s-examples: {uri-github-apple}/pkl-k8s-examples

For ready-to-go examples with full source code, see the various repositories that are available for you.

  • {uri-jvm-examples}[pkl-jvm-examples] -- for using Pkl within the JVM
  • {uri-swift-examples}[pkl-swift-examples] -- for using Pkl with Swift
  • {uri-go-examples}[pkl-go-examples] -- for using Pkl with Go
  • {uri-k8s-examples}[pkl-k8s-examples] -- for using Pkl with Kubernetes

File: docs/modules/ROOT/pages/index.adoc

= User Manual
include::../partials/component-attributes.adoc[]

Quick Links:
xref:pkl-cli:index.adoc#installation[Installation]
| xref:language-reference:index.adoc[Language Reference]
| https://pkl-lang.org/package-docs/pkl/current/index.html[Standard Library]

Pkl -- pronounced Pickle -- is an embeddable configuration language which provides rich support for data templating and validation.
It can be used from the command line, integrated in a build pipeline, or embedded in a program.
Pkl scales from small to large, simple to complex, ad-hoc to repetitive configuration tasks.

xref:introduction:index.adoc[Introduction]:: Why we created Pkl and what it can do for you.
xref:language.adoc[Language]:: Get to know the language and standard library.
xref:language-bindings.adoc[Bindings]:: Libraries for embedding Pkl into general-purpose languages.
xref:tools.adoc[Tools]:: CLI, Gradle plugin, code generators, and other tools.
link:{uri-pkl-examples-repo}[Examples]:: Ready-to-go examples with full source code.
xref:release-notes:index.adoc[Release Notes]:: What's new in each release.


File: docs/modules/ROOT/pages/integrations.adoc

= Framework Integrations

  • xref:spring:ROOT:index.adoc[Spring (Boot) Integration]

File: docs/modules/ROOT/pages/language.adoc

= Language

  • xref:language-tutorial:index.adoc[Tutorial]
  • xref:language-reference:index.adoc[Language Reference]
  • xref:standard-library.adoc[Standard Library]

File: docs/modules/ROOT/pages/language-bindings.adoc

= Language Bindings

  • xref:java-binding:index.adoc[Java]
  • xref:kotlin-binding:index.adoc[Kotlin]
  • xref:swift:ROOT:index.adoc[Swift]
  • xref:go:ROOT:index.adoc[Go]
  • xref:libpkl:index.adoc[libpkl]
  • xref:bindings-specification:index.adoc[Specification]
    ** xref:bindings-specification:message-passing-api.adoc[Message Passing API]
    ** xref:bindings-specification:binary-encoding.adoc[Pkl Binary Encoding]