g1t/apps/web/app/lib/project-kind.ts

82 lines3,948 bytesCodeBlame
1/**
2 * Words and links for a project that is a library or a tool rather than an
3 * app: which of its repository's packages to show, and how to publish a
4 * first one. Whether a project is one is decided by the projects service
5 * (`Project.kind`); this only says it on the pages.
6 */
7import type { DeploysSetting, Ecosystem, PackageSummary, ProjectEcosystem } from "@g1t/contracts";
8
9/** As lib/packages.ts names each registry; repeated so this module stands alone in tests. */
10const REGISTRY: Record<Ecosystem, string> = { container: "Container", npm: "npm", composer: "Composer", cargo: "Cargo", go: "Go" };
11
12const DOCS = "https://docs.g1t.sh";
13
14/** The choices for "Deployments for this project" in a project's settings. */
15export const DEPLOYS_CHOICES: { value: DeploysSetting; label: string; hint: string }[] = [
16 { value: "auto", label: "Detect automatically", hint: "From whether Deployments are on, the packages it publishes and the files at its root." },
17 { value: "yes", label: "Deploys", hint: "An app: its overview shows production, previews and domains." },
18 { value: "no", label: "Doesn't deploy", hint: "A library or a tool: its overview shows its packages and releases, and offers no deploying." },
19];
20
21/** A registry's guide, and the command that publishes a first version there. */
22export type PublishGuide = { label: string; guide: string; start: string | null };
23
24/** The registries with a guide, for a library whose files do not say which it is. */
25export const PUBLISH_GUIDES: PublishGuide[] = [
26 { label: "Composer", guide: `${DOCS}/guides/composer/`, start: "git tag v1.0.0 && git push --tags" },
27 { label: "npm", guide: `${DOCS}/guides/npm/`, start: "npm publish" },
28 { label: "Go", guide: `${DOCS}/guides/go/`, start: "git tag v1.0.0 && git push --tags" },
29 { label: "Containers", guide: `${DOCS}/guides/containers/`, start: null },
30];
31
32/** How a library of `ecosystem` publishes its first version; null when its files do not say. */
33export function publishGuide(ecosystem: ProjectEcosystem | null): PublishGuide | null {
34 switch (ecosystem) {
35 case "composer":
36 return PUBLISH_GUIDES[0]!;
37 case "npm":
38 return PUBLISH_GUIDES[1]!;
39 case "go":
40 return PUBLISH_GUIDES[2]!;
41 case "cargo":
42 return { label: "Cargo", guide: `${DOCS}/guides/packages/`, start: null };
43 case "python":
44 return { label: "Python", guide: `${DOCS}/guides/packages/`, start: null };
45 default:
46 return null;
47 }
48}
49
50/** A package as its own tool names it: `@acme/ui` for npm, the name otherwise. */
51export function packageName(pkg: Pick<PackageSummary, "ecosystem" | "name" | "workspace">): string {
52 return pkg.ecosystem === "npm" ? `@${pkg.workspace}/${pkg.name}` : pkg.name;
53}
54
55/** `Composer · psr/log 3.0.2`, for a project's card. */
56export function packageLine(pkg: Pick<PackageSummary, "ecosystem" | "name" | "workspace" | "latest">): string {
57 return `${REGISTRY[pkg.ecosystem]} · ${packageName(pkg)}${pkg.latest ? ` ${pkg.latest}` : ""}`;
58}
59
60/** The package's page. */
61export function packagePath(pkg: Pick<PackageSummary, "ecosystem" | "name" | "workspace">): string {
62 return `/${pkg.workspace}/-/packages/${pkg.ecosystem}/${pkg.name}`;
63}
64
65/**
66 * The packages a library's overview shows, from its repository's: what it
67 * publishes for others to install first, a container image last, as an
68 * image is how apps ship too.
69 */
70export function libraryPackages<T extends Pick<PackageSummary, "ecosystem" | "versions" | "updated_at">>(list: T[]): T[] {
71 return [...list].sort(
72 (a, b) =>
73 Number(a.ecosystem === "container") - Number(b.ecosystem === "container") ||
74 Number(b.versions > 0) - Number(a.versions > 0) ||
75 b.updated_at.localeCompare(a.updated_at),
76 );
77}
78
79/** Whether any of the packages has a version: a release is out. */
80export function hasRelease(list: Pick<PackageSummary, "versions">[]): boolean {
81 return list.some((pkg) => pkg.versions > 0);
82}