# Developing and publishing a package

A package lives in its own repository. To start one, run
`jadpo package new <Name> --library` or `--provider`. It writes the
package format, plus `recipes/`, a `sample/` app that the recipes and
tests run against, and `GUIDE.md`.

## Developing it

- `jadpo test` runs the package's tests, the examples in its
  descriptions, its decoders against its recordings, and its recipes
  compiled into `sample/`.
- `jadpo package record` and `conform` work against the provider's
  sandbox.
- `jadpo package check` runs the whole publishing bar locally, writes
  `surface.jadpo_record`, and compares it with the surface at the previous
  tag.

## Trying it in an app before publishing

`jadpo package link ../acme-pricing` compiles the app against the live
checkout and records the link in the lock. `jadpo build` for production,
and CI, refuse a link, so it can never ship. `jadpo package unlink`
restores the installed version.

## Private packages come from git

`jadpo package add github.com/acme/acme-pricing@v2.1.0` installs a
private package. A version is a git tag, which the package's CI adds only
after `jadpo package check` passes. Access is the developer's or CI's own
git access. There is no `jadpo login` and no private registry: packages
are committed into apps, so a registry's caching would add nothing.

## Public packages

Public packages go to the registry with `jadpo package publish`.

> `jadpo package link <folder>` writes `package
> Postcodes.v2 link ../postcodes` in the lock and keeps the line it
> replaced in `.jadpo/links`; from then on every `jadpo check`, `test` and
> `dev` reads the checkout's files in place of `packages/postcodes/v2/`,
> which stays as installed, and shows its problems at the checkout's paths.
> With `CI` set, `jadpo check` and `jadpo test` refuse the link
> (`install.link_refused`), and `jadpo build` will always. `jadpo package
> unlink postcodes` puts the installed line back:
>
> ```text
> $ jadpo package link ../postcodes
> ✓ Linked Postcodes.v2 to ../postcodes
>     checkout   ../postcodes
>     installed  2.1.0, restored by jadpo package unlink postcodes
>
> ✓ package linked  Postcodes.v2 · the app checks against it
>
> → jadpo package unlink postcodes  goes back to the installed version before you push
> ```

## What publishing requires

`jadpo package publish`, and `jadpo package check` before a tag, refuse a
package unless:

1. it compiles with no errors and no warnings;
2. every public type, failure, library and library function has a `///`
   description;
3. every function of a public library has at least one example in its
   description,
   compiled and run at publish, and every failure it can raise is shown by
   an example or a test;
4. its tests pass, every decoder decodes every recorded response, a
   field's decode and encode pair round-trips, and every recipe compiles
   and passes its tests in `sample/`;
5. its version agrees with the surface diff;
6. its changelog's list of changes is generated from the surface diff, and
   the author writes only why;
7. it declares a licence from the fixed list (not `.proprietary`, for the
   public registry) and the lowest Jadpo version it needs.

The bar applies only to what is published: the app's own integrations and
libraries skip it. Examples are part of the bar because they must run,
which the compiler can check.

A library package also ships complete wording in its own default locale,
with a `///` description on every public message
([Configuration and time](configuration-and-time.md)). The bar's
`wording` row, shown when the package carries translations, holds every
language the package ships to completeness, and item 2 asks for the
description of every public message.

> `jadpo package check`, run in a package's own
> repository, checks the package placed as the app's own integration in a
> scratch app (the golden rule) and shows each problem at its place in the
> package's folder. Item 1 is the check itself, `type.standard_exists` on
> the package's public types among it
> ([Standard library](standard-library.md)); item 2 is
> `publish.description_missing`; item 4's tests are the package's own
> `.test.jadpo` files; item 5 works out the version from the surface at
> the last tag and refuses a breaking change (`publish.breaking_change`);
> item 7 is the index's own check. Item 4's decoders are the `decoders`
> row, every decoder over every recording with each field's `decode:` and
> `encode:` round-tripping ("Recording errors"), and its recipes the
> `recipes` row (under "Recipes"). The surface is written whenever the
> package compiles and its version is allowed.
>
> Item 3: each ```` ```jadpo ```` block in a
> public declaration's `///` description runs as a test of the package,
> a function of a public library without one is
> `publish.example_missing`, as is a failure it can raise that no example
> or test asserts with `fails`, and an example that doesn't compile or hold
> is `publish.example_failed` at its line in the description. Item 6: the
> new version's section of `CHANGELOG.md` is written from the surface's
> changes, and a release whose section says nothing beneath the list is
> `publish.changelog_missing`:
>
> ```text
> $ jadpo package check
> Publishing bar
> ✓ compiles      passed                        no errors
> ✓ described     passed                        every public declaration
> ✓ examples      passed                        2 examples, every failure shown
> ✓ tests         passed                        3 tests
> ✓ version       passed                        2.1.0, 1 added since 2.0.0
> ✓ changelog     passed                        2.1.0 says why
> ✓ licence       passed                        mit, from Jadpo 1.0
>
> ✓ Wrote surface.jadpo_record and CHANGELOG.md
>
> ✓ package check passed  Postcodes.v2 2.1.0 · 7 passed
>
> → git tag v2.1.0  tags the release once surface.jadpo_record is committed
> ```
>
> An example is a test's body in the description; the changelog's list is
> the first list under its version, and the author writes why beneath it:
>
> ```text
> /// Reads a postcode in upper case.
> ///
> /// ```jadpo
> /// var postcode: UkPostcode = attempt uk.tidy("sw1a 1aa")
> /// assert postcode == "SW1A 1AA"
> /// assert uk.tidy("x") fails InvalidPostcode
> /// ```
> function tidy(entered: EnteredPostcode) fails InvalidPostcode -> UkPostcode {
> ```
>
> ```text
> # Changelog
>
> ## 2.1.0
>
> - added type `OutwardCode`
>
> Reads the outward code, for delivery zones.
>
> ## 2.0.0
>
> - first release
>
> UK postcodes, read as people type them.
> ```
