create-ailk 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -5
- package/component-catalog.json +146 -21
- package/component-catalog.md +9 -6
- package/dist/add-module-core.d.ts +22 -0
- package/dist/add-module-core.js +50 -0
- package/dist/add-module.d.ts +89 -0
- package/dist/add-module.js +334 -0
- package/dist/category-profile.d.ts +126 -0
- package/dist/category-profile.js +262 -0
- package/dist/cli.js +124 -13
- package/dist/copy.d.ts +14 -0
- package/dist/copy.js +38 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +6 -1
- package/dist/lib/extract-module-bundle.d.ts +76 -2
- package/dist/lib/extract-module-bundle.js +219 -8
- package/dist/lib/license-key-files.d.ts +15 -0
- package/dist/lib/license-key-files.js +102 -0
- package/dist/lib/module-license-gate.d.ts +6 -1
- package/dist/lib/module-license-gate.js +6 -1
- package/dist/lib/pro-callout.d.ts +16 -10
- package/dist/lib/pro-callout.js +27 -4
- package/dist/license-set.d.ts +34 -0
- package/dist/license-set.js +194 -0
- package/dist/module-architecture.d.ts +20 -0
- package/dist/module-architecture.js +77 -19
- package/dist/modules/commerce/0.6.0.tar.gz +0 -0
- package/dist/modules/commerce/0.6.1.tar.gz +0 -0
- package/dist/modules/docs-blog/0.6.0.tar.gz +0 -0
- package/dist/modules/docs-blog/0.6.1.tar.gz +0 -0
- package/dist/modules/marketing-site/0.6.1.tar.gz +0 -0
- package/dist/modules/minimalism-site/0.6.1.tar.gz +0 -0
- package/dist/modules/multi-tenant/0.6.0.tar.gz +0 -0
- package/dist/modules/multi-tenant/0.6.1.tar.gz +0 -0
- package/dist/modules/saas-product/0.6.1.tar.gz +0 -0
- package/dist/modules/scheduling/0.6.0.tar.gz +0 -0
- package/dist/modules/scheduling/0.6.1.tar.gz +0 -0
- package/dist/modules/signal-collectors/0.6.0.tar.gz +0 -0
- package/dist/modules/signal-collectors/0.6.1.tar.gz +0 -0
- package/dist/modules/simple-service/0.6.1.tar.gz +0 -0
- package/dist/modules/workspace/0.6.0.tar.gz +0 -0
- package/dist/modules/workspace/0.6.1.tar.gz +0 -0
- package/dist/parse-args.d.ts +7 -0
- package/dist/parse-args.js +23 -1
- package/dist/programmatic.d.ts +46 -0
- package/dist/programmatic.js +144 -19
- package/dist/site-chrome.d.ts +18 -7
- package/dist/site-chrome.js +32 -14
- package/dist/site-roster.d.ts +127 -0
- package/dist/site-roster.js +494 -0
- package/dist/surfaces.d.ts +20 -7
- package/dist/surfaces.js +149 -28
- package/dist/sync-routes.d.ts +9 -0
- package/dist/sync-routes.js +2 -2
- package/dist/template-manifest.d.ts +58 -2
- package/dist/template-manifest.js +196 -69
- package/package.json +6 -4
- package/site-templates/_base/content/en/BookCall/book-call.mdx +53 -0
- package/site-templates/_base/content/en/GlossaryList/glossary.mdx +66 -0
- package/site-templates/_base/content/en/NewsletterSignup/newsletter.mdx +68 -0
- package/site-templates/_base/content/en/Pricing/pricing.mdx +71 -62
- package/site-templates/_base/content/en/PrivacyPage/privacy.mdx +2 -3
- package/site-templates/_base/content/en/TermsPage/terms.mdx +2 -3
- package/site-templates/_base/content/en/UseCase/first-use-case.mdx +23 -0
- package/site-templates/_base/content/en/UseCase/second-use-case.mdx +23 -0
- package/site-templates/_base/content/en/UseCase/third-use-case.mdx +23 -0
- package/site-templates/designs/minimalism/DESIGN.md +162 -0
- package/site-templates/designs/standard/DESIGN.md +162 -0
- package/site-templates/marketing-site/DESIGN.md +162 -0
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +312 -57
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +209 -90
- package/site-templates/marketing-site/ailk-template.json +1 -0
- package/site-templates/marketing-site-free/DESIGN.md +162 -0
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +260 -66
- package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +294 -114
- package/site-templates/marketing-site-free/ailk-template.json +3 -2
- package/site-templates/minimalism-site/DESIGN.md +162 -0
- package/site-templates/minimalism-site/TEMPLATE-MANIFEST.json +246 -19
- package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +185 -51
- package/site-templates/minimalism-site/ailk-template.json +3 -2
- package/site-templates/minimalism-site/content/en/BookCall/book-call.mdx +53 -0
- package/site-templates/minimalism-site/content/en/ContactPage/contact.mdx +3 -37
- package/site-templates/minimalism-site/content/en/PurchasePolicyPage/purchase-policy.mdx +124 -0
- package/site-templates/saas-product/DESIGN.md +162 -0
- package/site-templates/simple-service/DESIGN.md +162 -0
- package/site-templates/simple-service/TEMPLATE-MANIFEST.json +135 -26
- package/site-templates/simple-service/TEMPLATE-MANIFEST.md +114 -59
- package/site-templates/simple-service/ailk-template.json +4 -3
- package/site-templates/simple-service/content/en/BookCall/book-call.mdx +53 -0
- package/site-templates/simple-service/content/en/ContactPage/contact.mdx +1 -36
- package/site-templates/simple-service/content/en/PurchasePolicyPage/purchase-policy.mdx +124 -0
- package/templates/.claude/settings.json +15 -0
- package/templates/.claude/skills/README.md +8 -8
- package/templates/.claude/skills/{scaffold-auth → add-auth}/SKILL.md +7 -7
- package/templates/.claude/skills/{scaffold-auth → add-auth}/references/env-vars.md +2 -2
- package/templates/.claude/skills/{scaffold-auth → add-auth}/references/oauth-app-setup.md +3 -3
- package/templates/.claude/skills/{scaffold-page → add-page}/SKILL.md +76 -62
- package/templates/.claude/skills/add-page/references/page-types.md +111 -0
- package/templates/.claude/skills/{scaffold-page → add-page}/templates/content.mdx.tmpl +4 -4
- package/templates/.claude/skills/{scaffold-page → add-page}/templates/route.tsx.tmpl +1 -1
- package/templates/.claude/skills/{audit-site → check-site}/SKILL.md +16 -17
- package/templates/.claude/skills/{audit-site → check-site}/references/common-errors.md +3 -3
- package/templates/.claude/skills/{audit-site → check-site}/references/findings-glossary.md +16 -14
- package/templates/.claude/skills/{audit-site → check-site}/references/severity-levels.md +1 -1
- package/templates/.claude/skills/fill-page/SKILL.md +180 -0
- package/templates/.claude/skills/fill-page/profiles/plumbing.yaml +80 -0
- package/templates/.claude/skills/fill-page/references/section-sources.md +41 -0
- package/templates/.claude/skills/{provision-config → setup-deploy}/SKILL.md +8 -8
- package/templates/.claude/skills/{provision-config → setup-deploy}/references/env-vars-template.md +2 -2
- package/templates/.claude/skills/{provision-config → setup-deploy}/references/runbook-template.md +8 -8
- package/templates/.claude/skills/{provision-config → setup-deploy}/references/vercel-json-template.md +1 -1
- package/templates/.claude/skills/upgrade-plan/SKILL.md +117 -0
- package/templates/.claude/skills/upgrade-plan/references/options.md +24 -0
- package/templates/.claude/skills/upgrade-plan/scripts/upgrade-plan.ts +527 -0
- package/templates/.github/workflows/ci.yml +5 -0
- package/templates/CLAUDE.md +10 -5
- package/templates/DESIGN.md +162 -0
- package/templates/README.md +134 -38
- package/templates/apps/api/.env.example +2 -1
- package/templates/apps/api/package.json +1 -1
- package/templates/apps/api/src/config/__tests__/index.test.ts +37 -2
- package/templates/apps/api/src/config/index.ts +19 -6
- package/templates/apps/api/src/lib/license-key-store.ts +45 -0
- package/templates/apps/api/src/lib/site.ts +5 -3
- package/templates/apps/api/src/middleware/__tests__/auth.database-not-configured.test.ts +97 -0
- package/templates/apps/api/src/middleware/auth.ts +9 -0
- package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +127 -5
- package/templates/apps/api/src/routes/content/get-page.ts +86 -2
- package/templates/apps/api/src/server.ts +6 -0
- package/templates/apps/mcp/__tests__/audit-single-page.test.ts +75 -1
- package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +57 -9
- package/templates/apps/mcp/package.json +2 -1
- package/templates/apps/mcp/src/index.ts +7 -0
- package/templates/apps/mcp/src/lib/audit-single-page.ts +36 -10
- package/templates/apps/mcp/src/lib/license-key-store.ts +45 -0
- package/templates/apps/web/PRODUCT.md +86 -0
- package/templates/apps/web/__tests__/setup.ts +18 -0
- package/templates/apps/web/app/[locale]/(auth)/forgot-password/forgot-password-card.tsx +10 -2
- package/templates/apps/web/app/[locale]/(auth)/layout.tsx +2 -2
- package/templates/apps/web/app/[locale]/(auth)/reset-password/reset-password-card.tsx +10 -4
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +22 -14
- package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +26 -18
- package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +12 -4
- package/templates/apps/web/app/[locale]/[slug]/__tests__/page.test.tsx +35 -4
- package/templates/apps/web/app/[locale]/[slug]/page.tsx +49 -9
- package/templates/apps/web/app/[locale]/book-a-call/page.tsx +50 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +3 -4
- package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +94 -33
- package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +53 -23
- package/templates/apps/web/app/[locale]/contact/__tests__/ContactForm.test.tsx +96 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +84 -2
- package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +5 -6
- package/templates/apps/web/app/[locale]/contact/page.tsx +25 -7
- package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +3 -4
- package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +4 -5
- package/templates/apps/web/app/[locale]/glossary/page.tsx +50 -0
- package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/how-to/page.tsx +25 -15
- package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/layout.tsx +113 -51
- package/templates/apps/web/app/[locale]/newsletter/page.tsx +50 -0
- package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +4 -5
- package/templates/apps/web/app/[locale]/{shipping → purchase-policy}/page.tsx +15 -10
- package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +4 -5
- package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +14 -1
- package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/software/page.tsx +25 -15
- package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/tech-articles/page.tsx +25 -15
- package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +3 -4
- package/templates/apps/web/app/[locale]/use-cases/[slug]/page.tsx +48 -0
- package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +3 -4
- package/templates/apps/web/app/[locale]/use-cases/page.tsx +15 -2
- package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/whitepapers/page.tsx +25 -15
- package/templates/apps/web/app/error-fallback.tsx +17 -45
- package/templates/apps/web/app/not-found.tsx +14 -38
- package/templates/apps/web/app/og/route.tsx +6 -0
- package/templates/apps/web/eslint.config.mjs +3 -0
- package/templates/apps/web/instrumentation.ts +14 -0
- package/templates/apps/web/lib/__tests__/site-theme.test.ts +135 -20
- package/templates/apps/web/lib/__tests__/structured-data.test.tsx +38 -0
- package/templates/apps/web/lib/license-key-store.ts +52 -0
- package/templates/apps/web/lib/nav-config.ts +64 -12
- package/templates/apps/web/lib/prisma-for-auth.ts +9 -6
- package/templates/apps/web/lib/site-brand.tsx +4 -8
- package/templates/apps/web/lib/site-chrome.ts +3 -3
- package/templates/apps/web/lib/site-identity.ts +134 -0
- package/templates/apps/web/lib/site-theme.ts +11 -0
- package/templates/apps/web/messages/en.json +52 -37
- package/templates/apps/web/middleware.ts +1 -1
- package/templates/apps/web/public/android-chrome-192x192.png +0 -0
- package/templates/apps/web/public/android-chrome-512x512.png +0 -0
- package/templates/apps/web/public/apple-touch-icon.png +0 -0
- package/templates/apps/web/public/favicon-16x16.png +0 -0
- package/templates/apps/web/public/favicon-32x32.png +0 -0
- package/templates/apps/web/public/favicon.ico +0 -0
- package/templates/apps/web/public/favicon.svg +3 -3
- package/templates/apps/web/public/logomark.svg +6 -3
- package/templates/apps/web/public/logos/ai-launch-kit-light.svg +4 -0
- package/templates/apps/web/public/logos/ai-launch-kit.svg +4 -0
- package/templates/apps/web/public/logos/atomic-agent-light.svg +4 -0
- package/templates/apps/web/public/logos/atomic-agent.svg +4 -0
- package/templates/apps/web/public/logos/salessmyth-light.svg +4 -0
- package/templates/apps/web/public/logos/salessmyth.svg +4 -0
- package/templates/apps/web/public/site.webmanifest +4 -4
- package/templates/apps/web/public/wordmark-light.svg +4 -0
- package/templates/apps/web/public/wordmark.svg +3 -3
- package/templates/apps/web/security-headers.config.ts +5 -1
- package/templates/apps/web/src/lib/commerce-sections.ts +35 -3
- package/templates/content/_site.mdx +41 -3
- package/templates/content/en/AboutPage/about.mdx +150 -144
- package/templates/content/en/BlogList/blog.mdx +105 -0
- package/templates/content/en/ContactPage/contact.mdx +44 -85
- package/templates/content/en/FAQPage/faq.mdx +86 -57
- package/templates/content/en/HomePage/home.mdx +276 -217
- package/templates/content/en/PurchasePolicyPage/purchase-policy.mdx +182 -0
- package/templates/content/en/SoftwareProduct/product.mdx +175 -0
- package/templates/content/en/UseCasesList/use-cases.mdx +170 -0
- package/templates/database/CHANGELOG.md +14 -0
- package/templates/database/package.json +3 -2
- package/templates/package.json +3 -1
- package/templates/tools/lint-architecture.ts +315 -0
- package/templates/tools/tsconfig.json +14 -0
- package/versions.json +33 -33
- package/templates/.claude/skills/add-schema/SKILL.md +0 -277
- package/templates/.claude/skills/add-schema/references/conflict-handling.md +0 -200
- package/templates/.claude/skills/add-schema/references/file-finding.md +0 -123
- package/templates/.claude/skills/add-schema/references/schema-types.md +0 -234
- package/templates/.claude/skills/scaffold-page/references/page-types.md +0 -169
- package/templates/.claude/skills/suggest-site-pages/SKILL.md +0 -242
- package/templates/.claude/skills/suggest-site-pages/references/categories.md +0 -287
- package/templates/apps/web/app/[locale]/cancellation/page.tsx +0 -44
- package/templates/apps/web/app/[locale]/returns/page.tsx +0 -44
- package/templates/apps/web/public/logo-dark.svg +0 -21
- package/templates/apps/web/public/logo-light.svg +0 -21
- package/templates/content/en/CancellationPolicyPage/cancellation.mdx +0 -108
- package/templates/content/en/LandingPage/blog.mdx +0 -83
- package/templates/content/en/LandingPage/features.mdx +0 -103
- package/templates/content/en/LandingPage/how-it-works.mdx +0 -143
- package/templates/content/en/ReturnsPolicyPage/returns.mdx +0 -108
- package/templates/content/en/ShippingPolicyPage/shipping.mdx +0 -108
package/dist/programmatic.js
CHANGED
|
@@ -15,21 +15,23 @@
|
|
|
15
15
|
* import { scaffoldSync } from './programmatic.js';
|
|
16
16
|
* const result = scaffoldSync({ targetDir: '/tmp/my-site', projectName: 'my-site' });
|
|
17
17
|
*/
|
|
18
|
-
import { existsSync, readdirSync, readFileSync, statSync, writeFileSync, } from "node:fs";
|
|
19
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
18
|
+
import { existsSync, readdirSync, readFileSync, rmdirSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
19
|
+
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
20
20
|
import { fileURLToPath } from "node:url";
|
|
21
|
+
import { AddModuleRefusedError, applyModuleToScaffold, } from "./add-module.js";
|
|
21
22
|
import { CATALOG_TARGET_PATH, writeComponentCatalog, } from "./component-catalog.js";
|
|
22
|
-
import { copyTemplate } from "./copy.js";
|
|
23
|
+
import { buildScaffoldMarkers, copyTemplate } from "./copy.js";
|
|
23
24
|
import { deriveArchitecture } from "./derive-architecture.js";
|
|
24
25
|
import { extractModuleBundle, installBundleTree, } from "./lib/extract-module-bundle.js";
|
|
25
26
|
import { fetchTemplate } from "./lib/fetch-template.js";
|
|
27
|
+
import { assertLicenseKeyShape, writeLicenseKeyFiles, } from "./lib/license-key-files.js";
|
|
26
28
|
import { resolvePaidModules } from "./lib/module-license-gate.js";
|
|
27
29
|
import { classifyModules } from "./lib/module-tier.js";
|
|
28
30
|
import { normalizeModules } from "./module-architecture.js";
|
|
29
31
|
import { SITE_CHROME_PATH, renderSiteChrome, resolveSiteChrome, } from "./site-chrome.js";
|
|
30
32
|
import { GATEABLE_SURFACES, MODULE_SURFACES, NAV_CONFIG_PATH, excludedRoutePaths, renderNavConfig, resolveSurfaces, } from "./surfaces.js";
|
|
31
33
|
import { syncRoutes } from "./sync-routes.js";
|
|
32
|
-
import { BASE_LAYER_DIR, mergeRoster, resolveTemplate, resolveTemplateLineage, templateDelivery, } from "./template-manifest.js";
|
|
34
|
+
import { BASE_LAYER_DIR, STARTER_DESIGNS, TemplateError, mergeRoster, resolveTemplate, resolveTemplateLineage, rosterDeclares, templateDelivery, } from "./template-manifest.js";
|
|
33
35
|
import { validateTarget } from "./validate.js";
|
|
34
36
|
const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
35
37
|
const TEMPLATES_DIR = resolve(PKG_ROOT, "templates");
|
|
@@ -92,15 +94,7 @@ export function scaffoldSync(opts) {
|
|
|
92
94
|
targetDir: targetAbs,
|
|
93
95
|
versions,
|
|
94
96
|
excludePaths: excludedRoutePaths(enabledSurfaces),
|
|
95
|
-
markers:
|
|
96
|
-
PROJECT_NAME: projectName,
|
|
97
|
-
COMPANY_NAME: "Your Company",
|
|
98
|
-
COMPANY_DOMAIN: "example.com",
|
|
99
|
-
// The social-profile handle the Free chrome's footer links carry
|
|
100
|
-
// (`https://x.com/{{COMPANY_HANDLE}}`, #5469 D5) — a placeholder the
|
|
101
|
-
// site owner replaces, never the kit vendor's own handle.
|
|
102
|
-
COMPANY_HANDLE: "yourcompany",
|
|
103
|
-
},
|
|
97
|
+
markers: buildScaffoldMarkers(projectName),
|
|
104
98
|
});
|
|
105
99
|
// Derive + write the module-set-driven architecture.yaml (spec #3787). This
|
|
106
100
|
// is the single source of the scaffolded site's code-boundary config and
|
|
@@ -118,7 +112,7 @@ export function scaffoldSync(opts) {
|
|
|
118
112
|
// template's `layout` block; a bare `scaffoldSync` call (every existing
|
|
119
113
|
// synchronous caller) writes DEFAULT_SITE_CHROME, byte-identical to the
|
|
120
114
|
// monorepo's own committed apps/web/lib/site-chrome.ts.
|
|
121
|
-
writeFileSync(join(targetAbs, SITE_CHROME_PATH), renderSiteChrome(resolveSiteChrome(opts.layout)));
|
|
115
|
+
writeFileSync(join(targetAbs, SITE_CHROME_PATH), renderSiteChrome(resolveSiteChrome(opts.layout, opts.design)));
|
|
122
116
|
// Opt-in only (#4636). Every write above this line is unconditional, so a
|
|
123
117
|
// scaffold with `withCatalog` unset touches exactly the files it did before.
|
|
124
118
|
if (opts.withCatalog === true)
|
|
@@ -154,10 +148,21 @@ export function scaffoldSync(opts) {
|
|
|
154
148
|
* with a paid module in `opts.modules` exercises the gate at all.
|
|
155
149
|
*/
|
|
156
150
|
export async function scaffold(opts) {
|
|
151
|
+
// #6683 D9 — refused before anything is fetched or written, like the
|
|
152
|
+
// template and design refusals below. The message never repeats the value.
|
|
153
|
+
if (opts.license !== undefined)
|
|
154
|
+
assertLicenseKeyShape(opts.license);
|
|
155
|
+
const licenseKey = opts.license ?? opts.licenseKey;
|
|
157
156
|
// Resolved first, and by the registry rather than re-validated here: the
|
|
158
157
|
// name already passed `parse-args.ts`, and `resolveTemplate` throws a
|
|
159
158
|
// `TemplateError` for a programmatic caller that skipped the parser.
|
|
160
159
|
const template = opts.template !== undefined ? resolveTemplate(opts.template) : undefined;
|
|
160
|
+
// #6638 — the design this scaffold renders: the caller's override, else the
|
|
161
|
+
// template's own. Unset for a scaffold naming neither.
|
|
162
|
+
const design = opts.design ?? template?.design;
|
|
163
|
+
if (design !== undefined && !STARTER_DESIGNS.includes(design)) {
|
|
164
|
+
throw new TemplateError(`unknown design "${design}". Declared: ${STARTER_DESIGNS.join(", ")}`);
|
|
165
|
+
}
|
|
161
166
|
// #5618 D2 — the `extends` chain is resolved in the client registry before
|
|
162
167
|
// any fetch: an unknown parent or a cycle is refused here, with the target
|
|
163
168
|
// still non-existent, like the four refusals below.
|
|
@@ -176,7 +181,7 @@ export async function scaffold(opts) {
|
|
|
176
181
|
const { paid } = classifyModules(modules);
|
|
177
182
|
const bundles = await resolvePaidModules({
|
|
178
183
|
paidModules: paid,
|
|
179
|
-
licenseKey
|
|
184
|
+
licenseKey,
|
|
180
185
|
...(template !== undefined ? { templateName: template.name } : {}),
|
|
181
186
|
...(opts.moduleRegistryUrl !== undefined
|
|
182
187
|
? { registryUrl: opts.moduleRegistryUrl }
|
|
@@ -197,7 +202,7 @@ export async function scaffold(opts) {
|
|
|
197
202
|
const templateBundle = template !== undefined && templateDelivery(template) === "paid"
|
|
198
203
|
? await fetchTemplate({
|
|
199
204
|
templateName: template.name,
|
|
200
|
-
token:
|
|
205
|
+
token: licenseKey ?? process.env["AILK_LICENSE_KEY"] ?? "",
|
|
201
206
|
...(opts.templateRegistryUrl !== undefined
|
|
202
207
|
? { registryUrl: opts.templateRegistryUrl }
|
|
203
208
|
: {}),
|
|
@@ -232,15 +237,25 @@ export async function scaffold(opts) {
|
|
|
232
237
|
...(surfaces !== undefined ? { surfaces } : {}),
|
|
233
238
|
// #5612 D1/D2 — the code registry's own `layout` block, known
|
|
234
239
|
// synchronously (unlike a bundle's `ailk-template.json`, only readable
|
|
235
|
-
// after install below). A template declaring none resolves to
|
|
236
|
-
//
|
|
240
|
+
// after install below). A template declaring none resolves to its
|
|
241
|
+
// design's knobs (#6638), and a `standard` one to the same defaults
|
|
242
|
+
// `scaffoldSync` already writes for a templateless scaffold.
|
|
237
243
|
...(template?.layout !== undefined ? { layout: template.layout } : {}),
|
|
244
|
+
...(design !== undefined ? { design } : {}),
|
|
238
245
|
});
|
|
239
246
|
// Threaded to extractModuleBundle for `package.json` patch targets'
|
|
240
247
|
// `workspace:*` substitution (spec 5418 § 3 D2) — the same version map
|
|
241
248
|
// `scaffoldSync` already reads for `copyTemplate`, re-read here since
|
|
242
249
|
// `scaffold()` doesn't share `scaffoldSync`'s call frame.
|
|
243
250
|
const versions = readVersionMap();
|
|
251
|
+
// #6460 — the SAME marker map `scaffoldSync` just substituted the base
|
|
252
|
+
// `templates/` copy with, rebuilt here from the same inputs (`scaffold()`
|
|
253
|
+
// does not share `scaffoldSync`'s call frame, exactly as `versions` above
|
|
254
|
+
// does not) and threaded into every layer that lands on top of it. Without
|
|
255
|
+
// it a `{{MARKER}}` authored in a base-layer or site-template file would
|
|
256
|
+
// survive into the scaffold verbatim — the state before this card, and the
|
|
257
|
+
// reason a template file could not carry the version stamp.
|
|
258
|
+
const markers = buildScaffoldMarkers(opts.projectName ?? basename(result.targetDir));
|
|
244
259
|
// #5618 D4 — the file-grain ownership registry for THIS scaffold: which
|
|
245
260
|
// layer wrote which destination. Call-scoped (a fresh Map per scaffold(),
|
|
246
261
|
// never module-level), threaded through every layer install below in the
|
|
@@ -267,6 +282,7 @@ export async function scaffold(opts) {
|
|
|
267
282
|
name: BASE_LAYER_DIR,
|
|
268
283
|
templateRequires: [],
|
|
269
284
|
versions,
|
|
285
|
+
markers,
|
|
270
286
|
ownership,
|
|
271
287
|
});
|
|
272
288
|
}
|
|
@@ -276,6 +292,7 @@ export async function scaffold(opts) {
|
|
|
276
292
|
targetDir: result.targetDir,
|
|
277
293
|
moduleName,
|
|
278
294
|
versions,
|
|
295
|
+
markers,
|
|
279
296
|
ownership,
|
|
280
297
|
});
|
|
281
298
|
}
|
|
@@ -305,6 +322,7 @@ export async function scaffold(opts) {
|
|
|
305
322
|
templateRequires: template.requires,
|
|
306
323
|
templateExtends: template.extends,
|
|
307
324
|
versions,
|
|
325
|
+
markers,
|
|
308
326
|
ownership,
|
|
309
327
|
})
|
|
310
328
|
: (() => {
|
|
@@ -319,15 +337,71 @@ export async function scaffold(opts) {
|
|
|
319
337
|
templateRequires: template.requires,
|
|
320
338
|
templateExtends: template.extends,
|
|
321
339
|
versions,
|
|
340
|
+
markers,
|
|
322
341
|
ownership,
|
|
323
342
|
});
|
|
324
343
|
})();
|
|
325
344
|
if (installed.layout !== undefined) {
|
|
326
|
-
writeFileSync(join(result.targetDir, SITE_CHROME_PATH), renderSiteChrome(resolveSiteChrome(installed.layout)));
|
|
345
|
+
writeFileSync(join(result.targetDir, SITE_CHROME_PATH), renderSiteChrome(resolveSiteChrome(installed.layout, design)));
|
|
327
346
|
}
|
|
347
|
+
pruneUnrosteredSeeds(result.targetDir, mergeRoster(template, template.requires), result.surfaces, ownership);
|
|
348
|
+
}
|
|
349
|
+
// #6683 D9 — persisted only after every layer landed, and only when the
|
|
350
|
+
// caller passed `license`: a scaffold without it writes nothing new.
|
|
351
|
+
if (opts.license !== undefined) {
|
|
352
|
+
writeLicenseKeyFiles(result.targetDir, opts.license);
|
|
328
353
|
}
|
|
329
354
|
return result;
|
|
330
355
|
}
|
|
356
|
+
/**
|
|
357
|
+
* The per-row install of the two SHARED seed layers (#6646 D1, disposition
|
|
358
|
+
* (b)): with every layer landed, remove each `content/en/**.mdx` that the
|
|
359
|
+
* `templates/` snapshot (the overlay — no `ownership` entry) or the `_base`
|
|
360
|
+
* layer wrote and no merged roster row names. Those two layers serve every
|
|
361
|
+
* template, so each carries seeds some templates do not roster (`/pricing`
|
|
362
|
+
* on a services site); a template's own tree and its modules' bundles are
|
|
363
|
+
* never pruned — a seed THEY ship without a row is drift, which the manifest
|
|
364
|
+
* generator's `--check` fails on instead.
|
|
365
|
+
*
|
|
366
|
+
* Merged over the template's own `requires`, as `rosterSurfaces` is: the
|
|
367
|
+
* rows that name shared-layer seeds are the template's own. A seed inside
|
|
368
|
+
* the content directory of a surface this scaffold ENABLES is kept too, so
|
|
369
|
+
* an explicit `--surfaces pricing` on a template that does not roster
|
|
370
|
+
* `/pricing` gets its route and its seed together.
|
|
371
|
+
*/
|
|
372
|
+
function pruneUnrosteredSeeds(targetDir, roster, surfaces, ownership) {
|
|
373
|
+
// `installBundleTree`'s ownership label for the base layer: it installs
|
|
374
|
+
// with `templateRequires: []`, so it records as a template. The overlay
|
|
375
|
+
// (the `templates/` snapshot) records no owner at all.
|
|
376
|
+
const shared = new Set([undefined, `template "${BASE_LAYER_DIR}"`]);
|
|
377
|
+
const enabledDirs = GATEABLE_SURFACES.filter((surface) => surfaces.includes(surface.id)).flatMap((surface) => surface.content.map((dir) => `${dir.replace("<locale>", "en")}/`));
|
|
378
|
+
const root = join(targetDir, "content", "en");
|
|
379
|
+
if (!existsSync(root))
|
|
380
|
+
return;
|
|
381
|
+
const stack = [root];
|
|
382
|
+
while (stack.length > 0) {
|
|
383
|
+
const dir = stack.pop();
|
|
384
|
+
if (dir === undefined)
|
|
385
|
+
break;
|
|
386
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
387
|
+
const abs = join(dir, entry.name);
|
|
388
|
+
if (entry.isDirectory()) {
|
|
389
|
+
stack.push(abs);
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
if (!entry.name.endsWith(".mdx"))
|
|
393
|
+
continue;
|
|
394
|
+
const path = relative(targetDir, abs).split(sep).join("/");
|
|
395
|
+
if (shared.has(ownership.get(path)) &&
|
|
396
|
+
!rosterDeclares(roster, path) &&
|
|
397
|
+
!enabledDirs.some((prefix) => path.startsWith(prefix))) {
|
|
398
|
+
rmSync(abs);
|
|
399
|
+
if (readdirSync(dir).length === 0)
|
|
400
|
+
rmdirSync(dir);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
331
405
|
/**
|
|
332
406
|
* The MODULE-LESS gateable-surface ids a template's merged roster names
|
|
333
407
|
* (#5469 D10): every `GATEABLE_SURFACES` entry no module contributes
|
|
@@ -474,6 +548,57 @@ export function syncRoutesSync(opts) {
|
|
|
474
548
|
versions: readVersionMap(),
|
|
475
549
|
});
|
|
476
550
|
}
|
|
551
|
+
/**
|
|
552
|
+
* Apply a purchased module to an already-scaffolded site in place
|
|
553
|
+
* (`create-ailk add-module`, #6653). The thin package-rooted wrapper around
|
|
554
|
+
* `add-module.ts`'s `applyModuleToScaffold`, the `syncRoutesSync` split:
|
|
555
|
+
*
|
|
556
|
+
* 1. the target must be an existing scaffold — the same check as the sync
|
|
557
|
+
* subcommands above;
|
|
558
|
+
* 2. a free module is refused before any key read or network call — it
|
|
559
|
+
* ships with every scaffold, there is no bundle to add;
|
|
560
|
+
* 3. `resolvePaidModules` — the SAME gate `scaffold()` runs, so a missing
|
|
561
|
+
* key or a key that does not cover the module is refused with the
|
|
562
|
+
* scaffold-time message, before anything is written;
|
|
563
|
+
* 4. the fetched bundle is merged under the plus-config policy.
|
|
564
|
+
*/
|
|
565
|
+
export async function addModule(opts) {
|
|
566
|
+
const targetAbs = resolve(opts.targetDir);
|
|
567
|
+
if (!existsSync(targetAbs)) {
|
|
568
|
+
throw new Error(`add-module target does not exist: ${targetAbs}. Point add-module at an already-scaffolded repo.`);
|
|
569
|
+
}
|
|
570
|
+
if (!statSync(targetAbs).isDirectory()) {
|
|
571
|
+
throw new Error(`add-module target is not a directory: ${targetAbs}`);
|
|
572
|
+
}
|
|
573
|
+
if (!existsSync(join(targetAbs, "architecture.yaml"))) {
|
|
574
|
+
throw new Error(`not a scaffolded repo: no architecture.yaml at ${targetAbs}. Run \`create-ailk <target-dir>\` to scaffold first.`);
|
|
575
|
+
}
|
|
576
|
+
const { paid } = classifyModules([opts.moduleName]);
|
|
577
|
+
if (paid.length === 0) {
|
|
578
|
+
throw new AddModuleRefusedError(`"${opts.moduleName}" ships with every scaffold — there is no module bundle to add`);
|
|
579
|
+
}
|
|
580
|
+
const bundles = await resolvePaidModules({
|
|
581
|
+
paidModules: paid,
|
|
582
|
+
licenseKey: opts.licenseKey,
|
|
583
|
+
...(opts.moduleRegistryUrl !== undefined
|
|
584
|
+
? { registryUrl: opts.moduleRegistryUrl }
|
|
585
|
+
: {}),
|
|
586
|
+
...(opts.fetchImpl !== undefined ? { fetchImpl: opts.fetchImpl } : {}),
|
|
587
|
+
});
|
|
588
|
+
const bundleBytes = bundles.get(opts.moduleName);
|
|
589
|
+
if (bundleBytes === undefined) {
|
|
590
|
+
throw new Error(`module "${opts.moduleName}": no bundle was resolved`);
|
|
591
|
+
}
|
|
592
|
+
return applyModuleToScaffold({
|
|
593
|
+
targetDir: targetAbs,
|
|
594
|
+
moduleName: opts.moduleName,
|
|
595
|
+
bundleBytes,
|
|
596
|
+
versions: readVersionMap(),
|
|
597
|
+
markers: buildScaffoldMarkers(basename(targetAbs)),
|
|
598
|
+
templatesDir: TEMPLATES_DIR,
|
|
599
|
+
siteTemplatesDir: SITE_TEMPLATES_DIR,
|
|
600
|
+
});
|
|
601
|
+
}
|
|
477
602
|
/** Re-exported so the CLI can name the file it wrote without duplicating it. */
|
|
478
603
|
export { CATALOG_TARGET_PATH };
|
|
479
604
|
/**
|
package/dist/site-chrome.d.ts
CHANGED
|
@@ -15,11 +15,17 @@
|
|
|
15
15
|
* `apps/web/lib/site-chrome.ts` every scaffold gets — beside `nav-config.ts`,
|
|
16
16
|
* the same GENERATED-header idiom (`surfaces.ts` `renderNavConfig`).
|
|
17
17
|
*
|
|
18
|
-
* Every field is optional and DEFAULTS to
|
|
19
|
-
*
|
|
20
|
-
* no
|
|
21
|
-
* monorepo's own
|
|
18
|
+
* Every field is optional and DEFAULTS to `full` / `columns` / `false` /
|
|
19
|
+
* `default` — the announcement banner is off unless a template turns it on
|
|
20
|
+
* (#6469). A scaffold naming no template, or a template naming no `layout`
|
|
21
|
+
* block, gets these defaults written, byte-identical to the monorepo's own
|
|
22
|
+
* committed `apps/web/lib/site-chrome.ts`.
|
|
23
|
+
*
|
|
24
|
+
* A template's DESIGN supplies layout knobs too (#6638): `DESIGN_LAYOUTS` in
|
|
25
|
+
* `template-manifest.ts`, read by `resolveSiteChrome`'s optional `design`
|
|
26
|
+
* argument between an explicit `layout` and these defaults.
|
|
22
27
|
*/
|
|
28
|
+
import { type StarterDesign } from "./template-manifest.js";
|
|
23
29
|
/** The `nav` knob's vocabulary. `mark-only` → the layout passes Nav an empty
|
|
24
30
|
* `navItems` (brand mark + the existing actions/theme/locale controls only). */
|
|
25
31
|
export type SiteChromeNav = "full" | "mark-only";
|
|
@@ -47,7 +53,7 @@ export interface ResolvedSiteChrome {
|
|
|
47
53
|
announcementBanner: boolean;
|
|
48
54
|
home: SiteChromeHome;
|
|
49
55
|
}
|
|
50
|
-
/**
|
|
56
|
+
/** Defaults (#5612 D1; banner off since #6469). */
|
|
51
57
|
export declare const DEFAULT_SITE_CHROME: ResolvedSiteChrome;
|
|
52
58
|
/** Template-relative path of the generated site-chrome registry — beside `NAV_CONFIG_PATH`. */
|
|
53
59
|
export declare const SITE_CHROME_PATH = "apps/web/lib/site-chrome.ts";
|
|
@@ -68,8 +74,13 @@ export declare class TemplateLayoutError extends Error {
|
|
|
68
74
|
* @param subject Caller-supplied context for the error message (e.g. `template "foo"`).
|
|
69
75
|
*/
|
|
70
76
|
export declare function validateTemplateLayout(value: unknown, subject: string): TemplateLayout;
|
|
71
|
-
/**
|
|
72
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Fill every field a `TemplateLayout` leaves unset — from `design`'s
|
|
79
|
+
* `DESIGN_LAYOUTS` entry when one is named (#6638), then from
|
|
80
|
+
* `DEFAULT_SITE_CHROME`. The explicit `layout` wins field by field, so a
|
|
81
|
+
* template can wear a design and still override one knob of it.
|
|
82
|
+
*/
|
|
83
|
+
export declare function resolveSiteChrome(layout?: TemplateLayout, design?: StarterDesign): ResolvedSiteChrome;
|
|
73
84
|
/**
|
|
74
85
|
* Render `apps/web/lib/site-chrome.ts` for a resolved layout — the same
|
|
75
86
|
* GENERATED-header idiom `renderNavConfig` uses. `layout.tsx` imports
|
package/dist/site-chrome.js
CHANGED
|
@@ -15,16 +15,22 @@
|
|
|
15
15
|
* `apps/web/lib/site-chrome.ts` every scaffold gets — beside `nav-config.ts`,
|
|
16
16
|
* the same GENERATED-header idiom (`surfaces.ts` `renderNavConfig`).
|
|
17
17
|
*
|
|
18
|
-
* Every field is optional and DEFAULTS to
|
|
19
|
-
*
|
|
20
|
-
* no
|
|
21
|
-
* monorepo's own
|
|
18
|
+
* Every field is optional and DEFAULTS to `full` / `columns` / `false` /
|
|
19
|
+
* `default` — the announcement banner is off unless a template turns it on
|
|
20
|
+
* (#6469). A scaffold naming no template, or a template naming no `layout`
|
|
21
|
+
* block, gets these defaults written, byte-identical to the monorepo's own
|
|
22
|
+
* committed `apps/web/lib/site-chrome.ts`.
|
|
23
|
+
*
|
|
24
|
+
* A template's DESIGN supplies layout knobs too (#6638): `DESIGN_LAYOUTS` in
|
|
25
|
+
* `template-manifest.ts`, read by `resolveSiteChrome`'s optional `design`
|
|
26
|
+
* argument between an explicit `layout` and these defaults.
|
|
22
27
|
*/
|
|
23
|
-
|
|
28
|
+
import { DESIGN_LAYOUTS, TemplateError, } from "./template-manifest.js";
|
|
29
|
+
/** Defaults (#5612 D1; banner off since #6469). */
|
|
24
30
|
export const DEFAULT_SITE_CHROME = {
|
|
25
31
|
nav: "full",
|
|
26
32
|
footer: "columns",
|
|
27
|
-
announcementBanner:
|
|
33
|
+
announcementBanner: false,
|
|
28
34
|
home: "default",
|
|
29
35
|
};
|
|
30
36
|
/** Template-relative path of the generated site-chrome registry — beside `NAV_CONFIG_PATH`. */
|
|
@@ -85,13 +91,25 @@ export function validateTemplateLayout(value, subject) {
|
|
|
85
91
|
}
|
|
86
92
|
return result;
|
|
87
93
|
}
|
|
88
|
-
/**
|
|
89
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Fill every field a `TemplateLayout` leaves unset — from `design`'s
|
|
96
|
+
* `DESIGN_LAYOUTS` entry when one is named (#6638), then from
|
|
97
|
+
* `DEFAULT_SITE_CHROME`. The explicit `layout` wins field by field, so a
|
|
98
|
+
* template can wear a design and still override one knob of it.
|
|
99
|
+
*/
|
|
100
|
+
export function resolveSiteChrome(layout, design) {
|
|
101
|
+
const fromDesign = design !== undefined ? DESIGN_LAYOUTS[design] : {};
|
|
102
|
+
// A JS caller (or a cast) can reach here with an undeclared design.
|
|
103
|
+
if (fromDesign === undefined) {
|
|
104
|
+
throw new TemplateError(`unknown design "${design}". Declared: ${Object.keys(DESIGN_LAYOUTS).join(", ")}`);
|
|
105
|
+
}
|
|
90
106
|
return {
|
|
91
|
-
nav: layout?.nav ?? DEFAULT_SITE_CHROME.nav,
|
|
92
|
-
footer: layout?.footer ?? DEFAULT_SITE_CHROME.footer,
|
|
93
|
-
announcementBanner: layout?.announcementBanner ??
|
|
94
|
-
|
|
107
|
+
nav: layout?.nav ?? fromDesign.nav ?? DEFAULT_SITE_CHROME.nav,
|
|
108
|
+
footer: layout?.footer ?? fromDesign.footer ?? DEFAULT_SITE_CHROME.footer,
|
|
109
|
+
announcementBanner: layout?.announcementBanner ??
|
|
110
|
+
fromDesign.announcementBanner ??
|
|
111
|
+
DEFAULT_SITE_CHROME.announcementBanner,
|
|
112
|
+
home: layout?.home ?? fromDesign.home ?? DEFAULT_SITE_CHROME.home,
|
|
95
113
|
};
|
|
96
114
|
}
|
|
97
115
|
/**
|
|
@@ -106,8 +124,8 @@ export function renderSiteChrome(resolved) {
|
|
|
106
124
|
//
|
|
107
125
|
// GENERATED by create-ailk from the declared template's \`layout\` block
|
|
108
126
|
// (#5612). A scaffold with no template, or a template with no \`layout\`
|
|
109
|
-
// block, gets
|
|
110
|
-
//
|
|
127
|
+
// block, gets the defaults below (the announcement banner is off unless a
|
|
128
|
+
// template turns it on, #6469). \`apps/web/app/[locale]/layout.tsx\` reads this to decide:
|
|
111
129
|
// - nav: "mark-only" → Nav renders the brand mark + right-hand controls
|
|
112
130
|
// only (no nav links).
|
|
113
131
|
// - footer: "centered" → Footer renders its existing centered variant.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { type PageRosterRow } from "./module-architecture.js";
|
|
2
|
+
import type { ModuleName } from "./parse-args.js";
|
|
3
|
+
import { type MarkerMap } from "./substitute.js";
|
|
4
|
+
import { type TemplateManifest } from "./template-manifest.js";
|
|
5
|
+
/** The site-root file that is the roster of record (#6658 D7). */
|
|
6
|
+
export declare const SITE_ROSTER_PATH = ".ailk-site-manifest.json";
|
|
7
|
+
/**
|
|
8
|
+
* Where a site scaffolded before #6658 carries its roster: the template's
|
|
9
|
+
* manifest copied to the root under its own name. Read only when
|
|
10
|
+
* `SITE_ROSTER_PATH` is absent, and written back in place.
|
|
11
|
+
*/
|
|
12
|
+
export declare const LEGACY_SITE_ROSTER_PATH = "TEMPLATE-MANIFEST.json";
|
|
13
|
+
/** One `rows[]` element: its parsed value and its verbatim text in the file. */
|
|
14
|
+
export interface RosterRowSlice {
|
|
15
|
+
value: Record<string, unknown>;
|
|
16
|
+
text: string;
|
|
17
|
+
}
|
|
18
|
+
/** A parsed manifest file, with the `rows` array located in its text. */
|
|
19
|
+
interface RosterFile {
|
|
20
|
+
doc: Record<string, unknown>;
|
|
21
|
+
text: string;
|
|
22
|
+
rows: RosterRowSlice[];
|
|
23
|
+
/** Index of the `rows` array's `[`. */
|
|
24
|
+
open: number;
|
|
25
|
+
/** Index of the `rows` array's `]`. */
|
|
26
|
+
close: number;
|
|
27
|
+
/** The whitespace before the first row and after the last — prettier's. */
|
|
28
|
+
lead: string;
|
|
29
|
+
trail: string;
|
|
30
|
+
}
|
|
31
|
+
/** The site's roster of record. */
|
|
32
|
+
export interface SiteRoster extends RosterFile {
|
|
33
|
+
/** The registry entry the file's `template` names. */
|
|
34
|
+
template: TemplateManifest;
|
|
35
|
+
/** The site-relative file it was read from — `SITE_ROSTER_PATH`, or the legacy root name. */
|
|
36
|
+
path: string;
|
|
37
|
+
}
|
|
38
|
+
/** One module contribution, with the generator's row(s) for its route. */
|
|
39
|
+
export interface ModuleRosterRow {
|
|
40
|
+
module: ModuleName;
|
|
41
|
+
contribution: PageRosterRow;
|
|
42
|
+
/**
|
|
43
|
+
* The generator's row for the route. For a `contentDir` contribution this
|
|
44
|
+
* is the code-route form (`kind: "route"`), used where the site has no
|
|
45
|
+
* seeds under the directory.
|
|
46
|
+
*/
|
|
47
|
+
row: RosterRowSlice;
|
|
48
|
+
/** A `contentDir` contribution's seeded page form. */
|
|
49
|
+
seeded?: RosterRowSlice;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The site's roster of record, or `undefined` when the site has none (a
|
|
53
|
+
* scaffold that named no template installs no manifest). A file that is not
|
|
54
|
+
* a JSON object, has no `rows` array or names a template the registry does
|
|
55
|
+
* not declare is refused: guessing would silently mis-roster the site.
|
|
56
|
+
*/
|
|
57
|
+
export declare function readSiteRoster(targetDir: string): SiteRoster | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* The generator's row for each of a module's `pageContributions`, in
|
|
60
|
+
* declaration order — read from the committed manifest of the first
|
|
61
|
+
* template (in `TEMPLATE_MANIFESTS` order) that requires the module, ships a
|
|
62
|
+
* manifest, and carries the route. A `contentDir` contribution resolves both
|
|
63
|
+
* of its forms. A route no shipped manifest carries is refused.
|
|
64
|
+
*/
|
|
65
|
+
export declare function moduleRosterRows(moduleName: ModuleName, siteTemplatesDir: string): ModuleRosterRow[];
|
|
66
|
+
/** What becomes of a superseded template row's seed file. */
|
|
67
|
+
export type SupersededSeed = {
|
|
68
|
+
path: string;
|
|
69
|
+
remove: true;
|
|
70
|
+
} | {
|
|
71
|
+
path: string;
|
|
72
|
+
remove: false;
|
|
73
|
+
wanted: string;
|
|
74
|
+
};
|
|
75
|
+
export interface RosterAppendPlan {
|
|
76
|
+
/** The rewritten file text, or undefined when the rows are unchanged. */
|
|
77
|
+
next: string | undefined;
|
|
78
|
+
/** Routes filled from the shipped reference rows. */
|
|
79
|
+
appended: string[];
|
|
80
|
+
/** The seeds of the template rows a module took over. */
|
|
81
|
+
seeds: SupersededSeed[];
|
|
82
|
+
}
|
|
83
|
+
export interface PlanRosterAppendOptions {
|
|
84
|
+
targetDir: string;
|
|
85
|
+
roster: SiteRoster;
|
|
86
|
+
/** The site's module set after the add. */
|
|
87
|
+
modules: readonly ModuleName[];
|
|
88
|
+
/** `moduleRosterRows` of every module in `modules`, resolved up front. */
|
|
89
|
+
references: readonly ModuleRosterRow[];
|
|
90
|
+
siteTemplatesDir: string;
|
|
91
|
+
templatesDir: string;
|
|
92
|
+
markers: MarkerMap;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The site roster's next `rows`: the template rows in file order, then each
|
|
96
|
+
* module's rows in `normalizeModules` order and, within a module, in
|
|
97
|
+
* `pageContributions` order — `mergeRoster`'s order, so adding A then B
|
|
98
|
+
* gives the roster adding B then A does.
|
|
99
|
+
*
|
|
100
|
+
* A row on a route a module in the set contributes is SUPERSEDED when it is
|
|
101
|
+
* the site template's own shipped row, untouched (the Free `/blog` teaser
|
|
102
|
+
* under docs-blog): the module's row takes its place, and its seed is
|
|
103
|
+
* removed only when its bytes are exactly what the scaffold installed. Any
|
|
104
|
+
* other row on a contributed route is the site's own and is kept as is.
|
|
105
|
+
*/
|
|
106
|
+
export declare function planRosterAppend(opts: PlanRosterAppendOptions): RosterAppendPlan;
|
|
107
|
+
export interface SiteRosterCheckOptions {
|
|
108
|
+
targetDir: string;
|
|
109
|
+
siteTemplatesDir: string;
|
|
110
|
+
templatesDir: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The site's roster problems — empty means clean. The scaffold-grained twin
|
|
114
|
+
* of `build-template-manifest.mjs --check`, over the same `rosterDeclares`
|
|
115
|
+
* predicate:
|
|
116
|
+
*
|
|
117
|
+
* 1. a route on more than one row;
|
|
118
|
+
* 2. a module in the site's set whose contributed row is missing, or is not
|
|
119
|
+
* the shipped reference row;
|
|
120
|
+
* 3. an installed seed — one some layer lands, present in the site — that
|
|
121
|
+
* the effective roster does not declare. A page the customer wrote is
|
|
122
|
+
* installed by no layer and is never reported.
|
|
123
|
+
*
|
|
124
|
+
* A site with no roster (a template-less scaffold) has no problems.
|
|
125
|
+
*/
|
|
126
|
+
export declare function siteRosterProblems(opts: SiteRosterCheckOptions): string[];
|
|
127
|
+
export {};
|