Packages
Bundle functions, a face, and their files into a package another program imports
A package is a folder with a kaya.json that names it. It holds Kaya
modules and any other files they use: a face's HTML, images, data. Another
package or a program imports the folder, and the functions it gets still find
their package's own files.
Packages compose. A general package can sit under a specialized one, and a program can sit on top:
storytelling/ tells a story scene by scene in a player face
kaya.json
main.kaya
player.html
pickleworths/ a show: its cast, their portraits and its own player;
kaya.json imports storytelling
main.kaya
player.html
portraits/
barnaby.png
episode-3/
main.kaya the story itself; imports pickleworthsThe story-episode example runs this project in your browser, portraits and all.
kaya.json
{
"name": "storytelling",
"version": "1.0.0",
"main": "main.kaya",
"description": "Tell a story scene by scene in a player face."
}name: lowercase letters, digits and hyphens, starting with a letter.version: letters, digits,.,-and+.main: the module an import of the folder brings in. It defaults tomain.kaya.descriptionis optional. Any other key is refused, so a misspelled field fails instead of being ignored.
Importing a package
Import the folder. The reference ends in /:
import tellStory from "../storytelling/"The names you import are functions defined in the package's main module. Importing a package runs none of its code and mounts nothing. Its functions run when you call them.
A package's modules may import one another, as ./scenes.kaya, and other
packages, as ../storytelling/. A path that leaves the package is refused
before the program runs.
A package's own files
A package declares the files it uses with resource, and its code reaches
them with asset(path:). The path is resolved beside the module whose code
calls asset(), so it finds the package's file wherever the caller lives:
// storytelling/main.kaya
resource "player.html"
function tellStory(title: string, scenes: json, face?: file): string {
let ownPlayer = asset(path: "player.html")
let player = face ?? ownPlayer
mount(component: "story-player", face: player, reads: ["story.scene"], sends: {"story.next": {zodTypeName: "Object", shape: {}}})
// ...
}Each package keeps its files apart. In the session they live under
.packages/<name>@<version>/, so storytelling and pickleworths can both
ship a player.html. A package's resources keep their own paths: as, in,
from and resources are for programs, not packages.
Specializing a package
A show changes what it needs by passing its own values. Here the show passes its own player face to the storytelling driver:
// pickleworths/main.kaya
import tellStory from "../storytelling/"
resource "player.html"
function playEpisode(title: string, scenes: json): string {
return tellStory(title: "The Pickleworths: {{title}}", scenes: scenes, face: asset(path: "player.html"))
}// episode-3/main.kaya
import playEpisode from "../pickleworths/"
let scenes = []
scenes.push(value: { speaker: "Barnaby", line: "Has anyone seen the garden gnome?" })
let ending = playEpisode(title: "Episode 3", scenes: scenes)
"{{ending}}"A face a package supplies is a face the program writes:
the viewer asks before it runs it the first time. A package's images reach its
face as pinned files: asset() returns each one with its size and digest, and
the face shows it with kaya.media().
Identity and copies
A package is identified by its name and version, not by its folder. Moving a
package's folder changes nothing for the program that imports it. One program
may use one copy of a package version: importing storytelling@1.0.0 from two
different folders is refused.
When a run first imports a package, it copies the package's files, and those of every package it depends on, into the session. A paused session that resumes later uses those copies, even if the folder has changed or moved.
Not yet
- Importing a package from a URL.
- Skills inside a package.