Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/canonical-manifest-category.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@ankhorage/templates': major
---

Emit the canonical AppManifest metadata category from generated starter manifests and update the contracts dependency to the manifest category contract.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# TEMPLATES

![license: MIT](././docs/badges/license.svg) ![npm: v2.1.0](././docs/badges/npm.svg) ![runtime: bun](././docs/badges/runtime.svg) ![typescript: strict](././docs/badges/typescript.svg) ![eslint: checked](././docs/badges/eslint.svg) ![prettier: checked](././docs/badges/prettier.svg) ![build: checked](././docs/badges/build.svg) ![tests: checked](././docs/badges/tests.svg) ![docs: paradox](././docs/badges/docs.svg)
![license: MIT](././docs/badges/license.svg) ![npm: v2.2.0](././docs/badges/npm.svg) ![runtime: bun](././docs/badges/runtime.svg) ![typescript: strict](././docs/badges/typescript.svg) ![eslint: checked](././docs/badges/eslint.svg) ![prettier: checked](././docs/badges/prettier.svg) ![build: checked](././docs/badges/build.svg) ![tests: checked](././docs/badges/tests.svg) ![docs: paradox](././docs/badges/docs.svg)

Reusable Ankhorage app templates, presets, and manifest generators.

Expand Down
4 changes: 2 additions & 2 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions docs/badges/npm.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 0 additions & 5 deletions docs/diagrams/architecture-overview.mmd
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ graph TD
module_src_catalog_ts["src/catalog.ts"]
package__ankhorage_templates -.-> module_src_catalog_ts
module_src_catalog_ts --> module_src_presets_category_presets_ts
module_src_catalog_ts --> module_src_templates_starter_categories_fallback_default_template_ts
module_src_catalog_ts --> module_src_templates_starter_categories_fallback_index_ts
module_src_catalog_ts --> module_src_templates_starter_index_ts
module_src_catalog_ts --> module_src_templateSelector_ts
module_src_cli_index_ts["src/cli/index.ts"]
Expand All @@ -28,7 +26,6 @@ graph TD
module_src_commands_ts --> module_src_commandContext_ts
module_src_commands_ts --> module_src_packageMetadata_ts
module_src_commands_ts --> module_src_projectSeed_ts
module_src_commands_ts --> module_src_templates_starter_index_ts
module_src_commands_ts --> module_src_templateSelector_ts
module_src_fixtures_oauth_ts["src/fixtures/oauth.ts"]
package__ankhorage_templates -.-> module_src_fixtures_oauth_ts
Expand Down Expand Up @@ -59,7 +56,6 @@ graph TD
package__ankhorage_templates -.-> module_src_presets_category_presets_ts
module_src_projectSeed_ts["src/projectSeed.ts"]
package__ankhorage_templates -.-> module_src_projectSeed_ts
module_src_projectSeed_ts --> module_src_templates_starter_index_ts
module_src_templates_shared_create_manifest_shell_ts["src/templates/shared/create-manifest-shell.ts"]
package__ankhorage_templates -.-> module_src_templates_shared_create_manifest_shell_ts
module_src_templates_shared_create_manifest_shell_ts --> module_src_internal_defaults_ts
Expand Down Expand Up @@ -758,4 +754,3 @@ graph TD
package__ankhorage_templates -.-> module_src_templates_starter_starter_types_ts
module_src_templateSelector_ts["src/templateSelector.ts"]
package__ankhorage_templates -.-> module_src_templateSelector_ts
module_src_templateSelector_ts --> module_src_templates_starter_index_ts
1 change: 1 addition & 0 deletions docs/diagrams/export-graph.mmd
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ graph LR
export_CategoryStarterTemplateDefinition -.-> export_StarterTemplateFactory
export_createCategoryAppManifest["createCategoryAppManifest"]
module_src_generators_create_category_app_ts --> export_createCategoryAppManifest
export_createCategoryAppManifest -.-> export_AppCategory
export_createCategoryAppManifest -.-> export_SplashScreenResizeMode
export_createOAuthFixtureManifest["createOAuthFixtureManifest"]
module_src_fixtures_oauth_ts --> export_createOAuthFixtureManifest
Expand Down
5 changes: 0 additions & 5 deletions docs/diagrams/module-relationships.mmd
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,6 @@ graph LR
module_src_templates_starter_starter_types_ts["src/templates/starter/starter.types.ts"]
module_src_templateSelector_ts["src/templateSelector.ts"]
module_src_catalog_ts --> module_src_presets_category_presets_ts
module_src_catalog_ts --> module_src_templates_starter_categories_fallback_default_template_ts
module_src_catalog_ts --> module_src_templates_starter_categories_fallback_index_ts
module_src_catalog_ts --> module_src_templates_starter_index_ts
module_src_catalog_ts --> module_src_templateSelector_ts
module_src_cli_index_ts --> module_src_commands_ts
Expand All @@ -189,7 +187,6 @@ graph LR
module_src_commands_ts --> module_src_commandContext_ts
module_src_commands_ts --> module_src_packageMetadata_ts
module_src_commands_ts --> module_src_projectSeed_ts
module_src_commands_ts --> module_src_templates_starter_index_ts
module_src_commands_ts --> module_src_templateSelector_ts
module_src_fixtures_oauth_ts --> module_src_generators_create_category_app_ts
module_src_fixtures_oauth_ts --> module_src_internal_merge_ts
Expand All @@ -201,7 +198,6 @@ graph LR
module_src_generators_create_category_app_ts --> module_src_templates_starter_index_ts
module_src_internal_merge_ts --> module_src_internal_overrides_ts
module_src_packageMetadata_ts --> module_package_json
module_src_projectSeed_ts --> module_src_templates_starter_index_ts
module_src_templates_shared_create_manifest_shell_ts --> module_src_internal_defaults_ts
module_src_templates_shared_create_manifest_shell_ts --> module_src_templates_shared_splash_screen_ts
module_src_templates_shared_create_theme_ts --> module_src_internal_defaults_ts
Expand Down Expand Up @@ -580,4 +576,3 @@ graph LR
module_src_templates_starter_starter_registry_ts --> module_src_templates_starter_starter_types_ts
module_src_templates_starter_starter_template_ts --> module_src_templates_starter_starter_registry_ts
module_src_templates_starter_starter_template_ts --> module_src_templates_starter_starter_types_ts
module_src_templateSelector_ts --> module_src_templates_starter_index_ts
38 changes: 19 additions & 19 deletions docs/exports.json

Large diffs are not rendered by default.

70 changes: 35 additions & 35 deletions docs/exports.md

Large diffs are not rendered by default.

1,009 changes: 499 additions & 510 deletions docs/index.html

Large diffs are not rendered by default.

206 changes: 85 additions & 121 deletions docs/paradox.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"version-packages": "changeset version"
},
"dependencies": {
"@ankhorage/contracts": "^3.0.0",
"@ankhorage/contracts": "^4.0.0",
"@ankhorage/zora": "^2.8.0"
},
"devDependencies": {
Expand Down
46 changes: 5 additions & 41 deletions src/catalog.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import type { AppManifest, ThemeConfig } from '@ankhorage/contracts';
import type { AppCategory, AppManifest } from '@ankhorage/contracts';

import { CATEGORY_PRESETS } from './presets/category-presets.js';
import { createFallbackStarterTemplate } from './templates/starter/categories/fallback/default.template.js';
import { fallbackStarterTemplates } from './templates/starter/categories/fallback/index.js';
import {
createStarterTemplate,
FALLBACK_TEMPLATE_CATEGORY,
listStarterTemplateSummaries,
type StarterTemplateCategory,
type StarterTemplateSummary,
type TemplateSeed,
} from './templates/starter/index.js';
Expand All @@ -16,18 +12,13 @@ import { createTemplateSelector } from './templateSelector.js';

export interface TemplateCatalogEntry {
readonly selector: string;
readonly category: StarterTemplateCategory;
readonly category: AppCategory;
readonly templateId: string;
readonly label: string;
readonly description: string;
}

const FALLBACK_THEME_HARMONY: ThemeConfig['light']['harmony'] = 'analogous';
const FALLBACK_FOCUS_AREAS = ['Home', 'Details', 'Settings'] as const;

export function listTemplateCatalog(
category?: StarterTemplateCategory,
): readonly TemplateCatalogEntry[] {
export function listTemplateCatalog(category?: AppCategory): readonly TemplateCatalogEntry[] {
const entries = createTemplateCatalogEntries();

if (category === undefined) {
Expand Down Expand Up @@ -72,27 +63,13 @@ export function createManifestForSelector(args: {
projectSlug: args.projectSlug,
});

if (args.selector.category === FALLBACK_TEMPLATE_CATEGORY) {
return createFallbackStarterTemplate(seed);
}

return createStarterTemplate(seed, {
templateId: args.selector.templateId,
});
}

function createTemplateCatalogEntries(): readonly TemplateCatalogEntry[] {
const fallbackEntries = fallbackStarterTemplates.map((template) => ({
selector: createTemplateSelector(FALLBACK_TEMPLATE_CATEGORY, template.id),
category: FALLBACK_TEMPLATE_CATEGORY,
templateId: template.id,
label: template.label,
description: template.description,
}));

const starterEntries = listStarterTemplateSummaries().map(createTemplateCatalogEntry);

return [...fallbackEntries, ...starterEntries];
return listStarterTemplateSummaries().map(createTemplateCatalogEntry);
}

function createTemplateCatalogEntry(summary: StarterTemplateSummary): TemplateCatalogEntry {
Expand All @@ -106,23 +83,10 @@ function createTemplateCatalogEntry(summary: StarterTemplateSummary): TemplateCa
}

function createTemplateSeed(args: {
readonly category: StarterTemplateCategory;
readonly category: AppCategory;
readonly displayName: string;
readonly projectSlug: string;
}): TemplateSeed {
if (args.category === FALLBACK_TEMPLATE_CATEGORY) {
return {
category: FALLBACK_TEMPLATE_CATEGORY,
categoryLabel: 'Fallback',
appName: args.displayName,
slug: args.projectSlug,
summary: 'Generic starter seed',
focusAreas: FALLBACK_FOCUS_AREAS,
primaryColor: '#2563EB',
harmony: FALLBACK_THEME_HARMONY,
};
}

const preset = CATEGORY_PRESETS[args.category];

return {
Expand Down
9 changes: 3 additions & 6 deletions src/commands.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { AppManifest } from '@ankhorage/contracts';
import type { AppCategory, AppManifest } from '@ankhorage/contracts';
import type { AnkhCapabilityId, AnkhCommandDescriptor } from '@ankhorage/contracts/cli';

import {
Expand All @@ -19,7 +19,6 @@ import {
type CreateProjectSeedRequest,
type ProjectSeedDependencies,
} from './projectSeed.js';
import type { StarterTemplateCategory } from './templates/starter/index.js';
import {
deriveDisplayNameFromSlug,
parseProjectSlug,
Expand Down Expand Up @@ -59,9 +58,7 @@ interface TemplatesCommandServices {
request: CreateProjectSeedRequest,
dependencies?: Partial<ProjectSeedDependencies>,
) => Promise<{ readonly projectPath: string }>;
readonly listTemplateCatalog: (
category?: StarterTemplateCategory,
) => readonly TemplateCatalogEntry[];
readonly listTemplateCatalog: (category?: AppCategory) => readonly TemplateCatalogEntry[];
readonly resolveTemplateCatalogEntry: typeof resolveTemplateCatalogEntry;
}

Expand Down Expand Up @@ -276,7 +273,7 @@ async function runCreateCommand(
return { exitCode: 0 };
}

function parseListArguments(argv: readonly string[]): StarterTemplateCategory | undefined {
function parseListArguments(argv: readonly string[]): AppCategory | undefined {
if (argv.length === 0) {
return undefined;
}
Expand Down
6 changes: 2 additions & 4 deletions src/projectSeed.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import { mkdir, stat, writeFile } from 'node:fs/promises';
import path from 'node:path';

import type { AppManifest } from '@ankhorage/contracts';

import type { StarterTemplateCategory } from './templates/starter/index.js';
import type { AppCategory, AppManifest } from '@ankhorage/contracts';

interface TemplateSeedMetadata {
readonly package: string;
readonly version: string;
readonly projectSlug: string;
readonly displayName: string;
readonly category: StarterTemplateCategory;
readonly category: AppCategory;
readonly templateId: string;
readonly selector: string;
}
Expand Down
15 changes: 3 additions & 12 deletions src/templateSelector.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import { APP_CATEGORIES, type AppCategory } from '@ankhorage/contracts';

import { FALLBACK_TEMPLATE_CATEGORY, type StarterTemplateCategory } from './templates/starter';

export interface ParsedTemplateSelector {
readonly category: StarterTemplateCategory;
readonly category: AppCategory;
readonly templateId: string;
readonly selector: string;
}

const PROJECT_SLUG_PATTERN = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/u;

export function parseTemplateCategory(value: string): StarterTemplateCategory {
if (value === FALLBACK_TEMPLATE_CATEGORY) {
return value;
}

export function parseTemplateCategory(value: string): AppCategory {
if (isAppCategory(value)) {
return value;
}
Expand Down Expand Up @@ -74,10 +68,7 @@ export function parseProjectSlug(value: string): string {
return normalizedValue;
}

export function createTemplateSelector(
category: StarterTemplateCategory,
templateId: string,
): string {
export function createTemplateSelector(category: AppCategory, templateId: string): string {
return `${category}/${templateId}`;
}

Expand Down
4 changes: 3 additions & 1 deletion src/templates/shared/create-manifest-shell.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { AppManifest, ThemeConfig } from '@ankhorage/contracts';
import type { AppCategory, AppManifest, ThemeConfig } from '@ankhorage/contracts';

import { BASE_INFRA, BASE_SETTINGS } from '../../internal/defaults';
import { createSplashScreen, type AppManifestWithSplashScreen } from './splash-screen';

interface ManifestShellSeed {
category: AppCategory;
appName: string;
slug: string;
}
Expand All @@ -20,6 +21,7 @@ export function createManifestShell(args: {
name: args.seed.appName,
slug: args.seed.slug,
version: args.version,
category: args.seed.category,
themeId: args.theme.id,
},
themes: [args.theme],
Expand Down
2 changes: 0 additions & 2 deletions src/templates/starter/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export {
FALLBACK_TEMPLATE_CATEGORY,
createStarterTemplate,
listStarterTemplateSummaries,
listStarterTemplates,
Expand All @@ -8,7 +7,6 @@ export {
TEMPLATE_KINDS,
type CategoryStarterTemplateDefinition,
type StarterTemplateFactory,
type StarterTemplateCategory,
type StarterTemplateId,
type StarterTemplateOptions,
type StarterTemplateSelection,
Expand Down
5 changes: 0 additions & 5 deletions src/templates/starter/starter.registry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { AppCategory } from '@ankhorage/contracts';

import { FALLBACK_TEMPLATE_CATEGORY } from './starter.types';
import { fallbackStarterTemplates } from './categories/fallback';
import { booksReadingStarterTemplates } from './categories/books-reading';
import { businessProductivityStarterTemplates } from './categories/business-productivity';
Expand Down Expand Up @@ -85,10 +84,6 @@ export function resolveStarterTemplate(
seed: TemplateSeed,
templateId = 'default',
): CategoryStarterTemplateDefinition {
if (seed.category === FALLBACK_TEMPLATE_CATEGORY) {
return resolveFallbackTemplate();
}

const categoryTemplates = STARTER_TEMPLATE_REGISTRY[seed.category];
const selected = categoryTemplates?.find((template) => template.id === templateId);
const categoryDefault = categoryTemplates?.find((template) => template.id === 'default');
Expand Down
11 changes: 2 additions & 9 deletions src/templates/starter/starter.template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,9 @@ import {
listStarterTemplatesByCategory,
resolveStarterTemplate,
} from './starter.registry';
import {
FALLBACK_TEMPLATE_CATEGORY,
TEMPLATE_KINDS,
type StarterTemplateCategory,
type StarterTemplateOptions,
type TemplateSeed,
} from './starter.types';
import { TEMPLATE_KINDS, type StarterTemplateOptions, type TemplateSeed } from './starter.types';

export { FALLBACK_TEMPLATE_CATEGORY, TEMPLATE_KINDS };
export { TEMPLATE_KINDS };
export {
listStarterTemplateSummaries,
listStarterTemplates,
Expand All @@ -24,7 +18,6 @@ export {
export type {
CategoryStarterTemplateDefinition,
StarterTemplateFactory,
StarterTemplateCategory,
StarterTemplateId,
StarterTemplateOptions,
StarterTemplateSelection,
Expand Down
6 changes: 1 addition & 5 deletions src/templates/starter/starter.types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import type { AppCategory, AppManifest, ThemeConfig } from '@ankhorage/contracts';

export const FALLBACK_TEMPLATE_CATEGORY = 'fallback' as const;

export type StarterTemplateCategory = AppCategory | typeof FALLBACK_TEMPLATE_CATEGORY;

export const TEMPLATE_KINDS = ['starter'] as const;

export type TemplateKind = (typeof TEMPLATE_KINDS)[number];
Expand All @@ -23,7 +19,7 @@ export interface StarterTemplateSummary {
}

export interface TemplateSeed {
category: StarterTemplateCategory;
category: AppCategory;
categoryLabel: string;
appName: string;
slug: string;
Expand Down
Loading
Loading