@c7-digital/scribe 0.0.1

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.
@@ -0,0 +1,224 @@
1
+ import { z } from "zod";
2
+ import type { RunOptions } from "./cli.js";
3
+ declare const ModuleConfigSchema: z.ZodObject<{
4
+ alias: z.ZodOptional<z.ZodString>;
5
+ templates: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
6
+ interfaces: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
7
+ }, "strip", z.ZodTypeAny, {
8
+ alias?: string | undefined;
9
+ templates?: string[] | undefined;
10
+ interfaces?: string[] | undefined;
11
+ }, {
12
+ alias?: string | undefined;
13
+ templates?: string[] | undefined;
14
+ interfaces?: string[] | undefined;
15
+ }>;
16
+ declare const VendorPackageConfigSchema: z.ZodObject<{
17
+ alias: z.ZodOptional<z.ZodString>;
18
+ modules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
19
+ alias: z.ZodOptional<z.ZodString>;
20
+ templates: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
21
+ interfaces: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
22
+ }, "strip", z.ZodTypeAny, {
23
+ alias?: string | undefined;
24
+ templates?: string[] | undefined;
25
+ interfaces?: string[] | undefined;
26
+ }, {
27
+ alias?: string | undefined;
28
+ templates?: string[] | undefined;
29
+ interfaces?: string[] | undefined;
30
+ }>>>;
31
+ }, "strip", z.ZodTypeAny, {
32
+ alias?: string | undefined;
33
+ modules?: Record<string, {
34
+ alias?: string | undefined;
35
+ templates?: string[] | undefined;
36
+ interfaces?: string[] | undefined;
37
+ }> | undefined;
38
+ }, {
39
+ alias?: string | undefined;
40
+ modules?: Record<string, {
41
+ alias?: string | undefined;
42
+ templates?: string[] | undefined;
43
+ interfaces?: string[] | undefined;
44
+ }> | undefined;
45
+ }>;
46
+ declare const ConfigFileSchema: z.ZodObject<{
47
+ schema: z.ZodLiteral<"1.0">;
48
+ input: z.ZodOptional<z.ZodString>;
49
+ output: z.ZodOptional<z.ZodObject<{
50
+ dir: z.ZodDefault<z.ZodString>;
51
+ bundle: z.ZodDefault<z.ZodBoolean>;
52
+ }, "strip", z.ZodTypeAny, {
53
+ dir: string;
54
+ bundle: boolean;
55
+ }, {
56
+ dir?: string | undefined;
57
+ bundle?: boolean | undefined;
58
+ }>>;
59
+ main: z.ZodOptional<z.ZodObject<{
60
+ pattern: z.ZodOptional<z.ZodString>;
61
+ modules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
62
+ alias: z.ZodOptional<z.ZodString>;
63
+ templates: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
64
+ interfaces: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
65
+ }, "strip", z.ZodTypeAny, {
66
+ alias?: string | undefined;
67
+ templates?: string[] | undefined;
68
+ interfaces?: string[] | undefined;
69
+ }, {
70
+ alias?: string | undefined;
71
+ templates?: string[] | undefined;
72
+ interfaces?: string[] | undefined;
73
+ }>>>;
74
+ }, "strip", z.ZodTypeAny, {
75
+ modules?: Record<string, {
76
+ alias?: string | undefined;
77
+ templates?: string[] | undefined;
78
+ interfaces?: string[] | undefined;
79
+ }> | undefined;
80
+ pattern?: string | undefined;
81
+ }, {
82
+ modules?: Record<string, {
83
+ alias?: string | undefined;
84
+ templates?: string[] | undefined;
85
+ interfaces?: string[] | undefined;
86
+ }> | undefined;
87
+ pattern?: string | undefined;
88
+ }>>;
89
+ vendor: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
90
+ alias: z.ZodOptional<z.ZodString>;
91
+ modules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
92
+ alias: z.ZodOptional<z.ZodString>;
93
+ templates: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
94
+ interfaces: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
95
+ }, "strip", z.ZodTypeAny, {
96
+ alias?: string | undefined;
97
+ templates?: string[] | undefined;
98
+ interfaces?: string[] | undefined;
99
+ }, {
100
+ alias?: string | undefined;
101
+ templates?: string[] | undefined;
102
+ interfaces?: string[] | undefined;
103
+ }>>>;
104
+ }, "strip", z.ZodTypeAny, {
105
+ alias?: string | undefined;
106
+ modules?: Record<string, {
107
+ alias?: string | undefined;
108
+ templates?: string[] | undefined;
109
+ interfaces?: string[] | undefined;
110
+ }> | undefined;
111
+ }, {
112
+ alias?: string | undefined;
113
+ modules?: Record<string, {
114
+ alias?: string | undefined;
115
+ templates?: string[] | undefined;
116
+ interfaces?: string[] | undefined;
117
+ }> | undefined;
118
+ }>>>;
119
+ compat: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
120
+ versions: z.ZodDefault<z.ZodArray<z.ZodObject<{
121
+ hash: z.ZodString;
122
+ version: z.ZodString;
123
+ }, "strip", z.ZodTypeAny, {
124
+ version: string;
125
+ hash: string;
126
+ }, {
127
+ version: string;
128
+ hash: string;
129
+ }>, "many">>;
130
+ }, "strip", z.ZodTypeAny, {
131
+ versions: {
132
+ version: string;
133
+ hash: string;
134
+ }[];
135
+ }, {
136
+ versions?: {
137
+ version: string;
138
+ hash: string;
139
+ }[] | undefined;
140
+ }>>>;
141
+ }, "strip", z.ZodTypeAny, {
142
+ schema: "1.0";
143
+ main?: {
144
+ modules?: Record<string, {
145
+ alias?: string | undefined;
146
+ templates?: string[] | undefined;
147
+ interfaces?: string[] | undefined;
148
+ }> | undefined;
149
+ pattern?: string | undefined;
150
+ } | undefined;
151
+ vendor?: Record<string, {
152
+ alias?: string | undefined;
153
+ modules?: Record<string, {
154
+ alias?: string | undefined;
155
+ templates?: string[] | undefined;
156
+ interfaces?: string[] | undefined;
157
+ }> | undefined;
158
+ }> | undefined;
159
+ input?: string | undefined;
160
+ output?: {
161
+ dir: string;
162
+ bundle: boolean;
163
+ } | undefined;
164
+ compat?: Record<string, {
165
+ versions: {
166
+ version: string;
167
+ hash: string;
168
+ }[];
169
+ }> | undefined;
170
+ }, {
171
+ schema: "1.0";
172
+ main?: {
173
+ modules?: Record<string, {
174
+ alias?: string | undefined;
175
+ templates?: string[] | undefined;
176
+ interfaces?: string[] | undefined;
177
+ }> | undefined;
178
+ pattern?: string | undefined;
179
+ } | undefined;
180
+ vendor?: Record<string, {
181
+ alias?: string | undefined;
182
+ modules?: Record<string, {
183
+ alias?: string | undefined;
184
+ templates?: string[] | undefined;
185
+ interfaces?: string[] | undefined;
186
+ }> | undefined;
187
+ }> | undefined;
188
+ input?: string | undefined;
189
+ output?: {
190
+ dir?: string | undefined;
191
+ bundle?: boolean | undefined;
192
+ } | undefined;
193
+ compat?: Record<string, {
194
+ versions?: {
195
+ version: string;
196
+ hash: string;
197
+ }[] | undefined;
198
+ }> | undefined;
199
+ }>;
200
+ export type ConfigFile = z.infer<typeof ConfigFileSchema>;
201
+ export type ModuleOverride = z.infer<typeof ModuleConfigSchema>;
202
+ export type VendorOverride = z.infer<typeof VendorPackageConfigSchema>;
203
+ export interface ResolvedConfig {
204
+ input: string;
205
+ output: {
206
+ dir: string;
207
+ bundle: boolean;
208
+ };
209
+ main: {
210
+ pattern?: string;
211
+ modules?: Record<string, ModuleOverride>;
212
+ };
213
+ vendor?: Record<string, VendorOverride>;
214
+ compat: Record<string, {
215
+ versions: Array<{
216
+ hash: string;
217
+ version: string;
218
+ }>;
219
+ }>;
220
+ version?: string;
221
+ dryRun: boolean;
222
+ }
223
+ export declare function loadConfig(opts: RunOptions): Promise<ResolvedConfig>;
224
+ export {};
@@ -0,0 +1,59 @@
1
+ import { z } from "zod";
2
+ import { readFile } from "node:fs/promises";
3
+ import { resolve } from "node:path";
4
+ import YAML from "yaml";
5
+ // --- Zod schemas ---
6
+ const TemplateListSchema = z.array(z.string()).optional();
7
+ const ModuleConfigSchema = z.object({
8
+ alias: z.string().optional(),
9
+ templates: TemplateListSchema,
10
+ interfaces: z.array(z.string()).optional(),
11
+ });
12
+ const MainConfigSchema = z.object({
13
+ pattern: z.string().optional(),
14
+ modules: z.record(z.string(), ModuleConfigSchema).optional(),
15
+ });
16
+ const VendorPackageConfigSchema = z.object({
17
+ alias: z.string().optional(),
18
+ modules: z.record(z.string(), ModuleConfigSchema).optional(),
19
+ });
20
+ const CompatVersionSchema = z.object({
21
+ hash: z.string(),
22
+ version: z.string(),
23
+ });
24
+ const CompatPackageSchema = z.object({
25
+ versions: z.array(CompatVersionSchema).default([]),
26
+ });
27
+ const CompatConfigSchema = z.record(z.string(), CompatPackageSchema);
28
+ const OutputConfigSchema = z.object({
29
+ dir: z.string().default("dist"),
30
+ bundle: z.boolean().default(true),
31
+ });
32
+ const ConfigFileSchema = z.object({
33
+ schema: z.literal("1.0"),
34
+ input: z.string().optional(),
35
+ output: OutputConfigSchema.optional(),
36
+ main: MainConfigSchema.optional(),
37
+ vendor: z.record(z.string(), VendorPackageConfigSchema).optional(),
38
+ compat: CompatConfigSchema.optional(),
39
+ });
40
+ export async function loadConfig(opts) {
41
+ let file;
42
+ if (opts.config) {
43
+ const raw = await readFile(resolve(opts.config), "utf-8");
44
+ const parsed = YAML.parse(raw);
45
+ file = ConfigFileSchema.parse(parsed);
46
+ }
47
+ const input = opts.input ?? file?.input ?? "./codegen/js";
48
+ const outputDir = opts.output ?? file?.output?.dir ?? "dist";
49
+ const bundle = file?.output?.bundle ?? true;
50
+ return {
51
+ input: resolve(input),
52
+ output: { dir: resolve(outputDir), bundle },
53
+ main: { pattern: file?.main?.pattern, modules: file?.main?.modules },
54
+ vendor: file?.vendor,
55
+ compat: file?.compat ?? {},
56
+ version: opts.version ?? process.env["DAR_VERSION"],
57
+ dryRun: opts.dryRun ?? false,
58
+ };
59
+ }
@@ -0,0 +1,13 @@
1
+ import type { ResolvedConfig } from "./config.js";
2
+ export type PackageRole = "main" | "vendor" | "stdlib";
3
+ export interface DiscoveredPackage {
4
+ /** Directory name, e.g. "domain-verification-model-0.0.8" */
5
+ name: string;
6
+ /** Absolute path to the package directory */
7
+ path: string;
8
+ /** Classified role */
9
+ role: PackageRole;
10
+ /** Version extracted from directory name, e.g. "0.0.8" */
11
+ detectedVersion?: string;
12
+ }
13
+ export declare function discoverPackages(config: ResolvedConfig): Promise<DiscoveredPackage[]>;
@@ -0,0 +1,70 @@
1
+ import { readdir } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { rcompare } from "semver";
4
+ const STDLIB_PREFIXES = ["daml-prim-", "daml-stdlib-", "ghc-stdlib-"];
5
+ const VENDOR_PREFIXES = ["splice-"];
6
+ function globToRegex(pattern) {
7
+ return new RegExp("^" + pattern.replace(/\*/g, ".*") + "$");
8
+ }
9
+ function classifyPackage(name, mainPattern, vendorPatterns) {
10
+ if (STDLIB_PREFIXES.some((p) => name.startsWith(p)))
11
+ return "stdlib";
12
+ if (mainPattern) {
13
+ if (globToRegex(mainPattern).test(name))
14
+ return "main";
15
+ }
16
+ // If vendor patterns are explicitly specified, only match those
17
+ if (vendorPatterns && vendorPatterns.length > 0) {
18
+ if (vendorPatterns.some((p) => globToRegex(p).test(name)))
19
+ return "vendor";
20
+ // If it doesn't match any vendor pattern and isn't main/stdlib, still classify
21
+ // based on known prefixes but mark as stdlib (skip it)
22
+ if (VENDOR_PREFIXES.some((p) => name.startsWith(p)))
23
+ return "stdlib";
24
+ // Non-vendor, non-stdlib, non-main pattern => candidate for main
25
+ return mainPattern ? "stdlib" : "main";
26
+ }
27
+ if (VENDOR_PREFIXES.some((p) => name.startsWith(p)))
28
+ return "vendor";
29
+ // If no mainPattern was given, non-stdlib non-vendor packages are candidates for main
30
+ return mainPattern ? "vendor" : "main";
31
+ }
32
+ function extractVersion(name) {
33
+ // Match trailing version: "my-project-0.1.0" -> "0.1.0"
34
+ const match = name.match(/-(\d+\.\d+\.\d+(?:[.-].*)?)$/);
35
+ return match?.[1];
36
+ }
37
+ export async function discoverPackages(config) {
38
+ const entries = await readdir(config.input, { withFileTypes: true });
39
+ const dirs = entries.filter((e) => e.isDirectory() || e.isSymbolicLink());
40
+ const vendorPatterns = config.vendor
41
+ ? Object.keys(config.vendor)
42
+ : undefined;
43
+ let packages = dirs.map((entry) => ({
44
+ name: entry.name,
45
+ path: join(config.input, entry.name),
46
+ role: classifyPackage(entry.name, config.main.pattern, vendorPatterns),
47
+ detectedVersion: extractVersion(entry.name),
48
+ }));
49
+ // If multiple main packages match (e.g., model-0.0.7, model-0.0.8, model-0.0.9),
50
+ // select the one matching config.version, or the latest version.
51
+ const mainPackages = packages.filter((p) => p.role === "main");
52
+ if (mainPackages.length > 1) {
53
+ const targetVersion = config.version;
54
+ let selected;
55
+ if (targetVersion) {
56
+ selected = mainPackages.find((p) => p.detectedVersion === targetVersion);
57
+ if (!selected) {
58
+ const names = mainPackages.map((p) => p.name).join(", ");
59
+ throw new Error(`Version ${targetVersion} not found among main packages: ${names}`);
60
+ }
61
+ }
62
+ else {
63
+ // Pick the latest version (sort semver descending)
64
+ selected = mainPackages.sort((a, b) => rcompare(a.detectedVersion ?? "0.0.0", b.detectedVersion ?? "0.0.0"))[0];
65
+ }
66
+ // Demote non-selected main packages to stdlib (they'll be included for bundling but not exported)
67
+ packages = packages.map((p) => p.role === "main" && p !== selected ? { ...p, role: "stdlib" } : p);
68
+ }
69
+ return packages;
70
+ }
@@ -0,0 +1,13 @@
1
+ import type { AnalyzedPackage } from "../analyze.js";
2
+ /**
3
+ * Generate import statements for all modules across all packages.
4
+ *
5
+ * For main package modules: import from the module.js file directly.
6
+ * For vendor packages: import from lib/index.js (package-level) and
7
+ * also from individual modules if they're explicitly included.
8
+ */
9
+ export declare function generateImports(mainPkg: AnalyzedPackage | undefined, vendorPkgs: AnalyzedPackage[], stdlibPkgs: AnalyzedPackage[]): string;
10
+ /**
11
+ * Generate named export statements for all user-facing modules.
12
+ */
13
+ export declare function generateExportStatements(mainPkg: AnalyzedPackage | undefined, vendorPkgs: AnalyzedPackage[]): string;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Generate import statements for all modules across all packages.
3
+ *
4
+ * For main package modules: import from the module.js file directly.
5
+ * For vendor packages: import from lib/index.js (package-level) and
6
+ * also from individual modules if they're explicitly included.
7
+ */
8
+ export function generateImports(mainPkg, vendorPkgs, stdlibPkgs) {
9
+ const lines = [];
10
+ lines.push("// Generated by @c7-digital/scribe");
11
+ lines.push("");
12
+ // Main package modules
13
+ if (mainPkg) {
14
+ for (const mod of mainPkg.modules) {
15
+ const relPath = `./${mainPkg.name}/lib/${mod.modulePath}.js`;
16
+ lines.push(`import * as ${mod.alias} from '${relPath}';`);
17
+ }
18
+ }
19
+ // Vendor packages: import both the package-level index and specific modules
20
+ for (const vendor of vendorPkgs) {
21
+ // Package-level import (gives access to packageId)
22
+ const pkgAlias = sanitizeAlias(vendor.name);
23
+ lines.push(`import * as ${pkgAlias} from './${vendor.name}/lib/index.js';`);
24
+ // Individual module imports
25
+ for (const mod of vendor.modules) {
26
+ const relPath = `./${vendor.name}/lib/${mod.modulePath}.js`;
27
+ lines.push(`import * as ${mod.alias} from '${relPath}';`);
28
+ }
29
+ }
30
+ // Stdlib packages: import package-level (needed for bundling, not exported)
31
+ for (const stdlib of stdlibPkgs) {
32
+ const alias = sanitizeAlias(stdlib.name);
33
+ lines.push(`import * as ${alias} from './${stdlib.name}/lib/index.js';`);
34
+ }
35
+ lines.push("");
36
+ lines.push("import * as version from './version.js';");
37
+ return lines.join("\n");
38
+ }
39
+ /**
40
+ * Generate named export statements for all user-facing modules.
41
+ */
42
+ export function generateExportStatements(mainPkg, vendorPkgs) {
43
+ const lines = [];
44
+ // Collect all export names
45
+ const exportNames = [];
46
+ if (mainPkg) {
47
+ for (const mod of mainPkg.modules) {
48
+ exportNames.push(mod.alias);
49
+ }
50
+ }
51
+ for (const vendor of vendorPkgs) {
52
+ for (const mod of vendor.modules) {
53
+ exportNames.push(mod.alias);
54
+ }
55
+ }
56
+ if (exportNames.length > 0) {
57
+ lines.push(`export { ${exportNames.join(", ")} };`);
58
+ }
59
+ lines.push("export { PACKAGE_VERSION } from './version.js';");
60
+ return lines.join("\n");
61
+ }
62
+ /** Sanitize a package directory name to a valid JS identifier. */
63
+ function sanitizeAlias(name) {
64
+ return name.replace(/[-. ]/g, "_");
65
+ }
@@ -0,0 +1,13 @@
1
+ import type { AnalyzedPackage } from "../analyze.js";
2
+ import type { ResolvedConfig } from "../config.js";
3
+ export { generateImports, generateExportStatements } from "./exports.js";
4
+ export { generateRegistry } from "./registry.js";
5
+ export { generateTypeDefs, generateVersionTypeDef } from "./types.js";
6
+ export interface GenerateResult {
7
+ mainPkg?: AnalyzedPackage;
8
+ vendorPkgs: AnalyzedPackage[];
9
+ stdlibPkgs: AnalyzedPackage[];
10
+ outputDir: string;
11
+ files: string[];
12
+ }
13
+ export declare function generate(packages: AnalyzedPackage[], config: ResolvedConfig): Promise<GenerateResult>;
@@ -0,0 +1,91 @@
1
+ import { mkdir, writeFile, symlink, readdir, rm, copyFile } from "node:fs/promises";
2
+ import { join, resolve } from "node:path";
3
+ import { generateImports, generateExportStatements } from "./exports.js";
4
+ import { generateRegistry } from "./registry.js";
5
+ import { generateTypeDefs, generateVersionTypeDef } from "./types.js";
6
+ import { bundle } from "../transform.js";
7
+ export { generateImports, generateExportStatements } from "./exports.js";
8
+ export { generateRegistry } from "./registry.js";
9
+ export { generateTypeDefs, generateVersionTypeDef } from "./types.js";
10
+ export async function generate(packages, config) {
11
+ const mainPkg = packages.find((p) => p.role === "main");
12
+ const vendorPkgs = packages.filter((p) => p.role === "vendor");
13
+ const stdlibPkgs = packages.filter((p) => p.role === "stdlib");
14
+ // Determine version for the main package
15
+ const version = config.version ?? mainPkg?.version ?? "0.0.0";
16
+ if (mainPkg) {
17
+ mainPkg.version = version;
18
+ }
19
+ if (config.dryRun) {
20
+ printSummary(mainPkg, vendorPkgs, config);
21
+ return { mainPkg, vendorPkgs, stdlibPkgs, outputDir: config.output.dir, files: [] };
22
+ }
23
+ // Prepare a staging directory (.scribe/) adjacent to output
24
+ const outputDir = config.output.dir;
25
+ const srcDir = resolve(outputDir, "..", ".scribe");
26
+ // Clean and recreate .scribe/
27
+ await rm(srcDir, { recursive: true, force: true });
28
+ await mkdir(srcDir, { recursive: true });
29
+ // Symlink all input packages into src/
30
+ const inputEntries = await readdir(config.input, { withFileTypes: true });
31
+ for (const entry of inputEntries) {
32
+ if (entry.isDirectory() || entry.isSymbolicLink()) {
33
+ const target = resolve(join(config.input, entry.name));
34
+ const link = join(srcDir, entry.name);
35
+ await symlink(target, link);
36
+ }
37
+ }
38
+ // Generate version.js
39
+ await writeFile(join(srcDir, "version.js"), `export const PACKAGE_VERSION = '${version}';\n`);
40
+ // Generate index.js
41
+ const indexJs = [
42
+ generateImports(mainPkg, vendorPkgs, stdlibPkgs),
43
+ "",
44
+ generateExportStatements(mainPkg, vendorPkgs),
45
+ generateRegistry(mainPkg, vendorPkgs, config),
46
+ ].join("\n");
47
+ await writeFile(join(srcDir, "index.js"), indexJs);
48
+ // Generate index.d.ts
49
+ const indexDts = generateTypeDefs(mainPkg, vendorPkgs);
50
+ await writeFile(join(srcDir, "index.d.ts"), indexDts);
51
+ // Generate version.d.ts
52
+ await writeFile(join(srcDir, "version.d.ts"), generateVersionTypeDef());
53
+ const files = [".scribe/index.js", ".scribe/index.d.ts", ".scribe/version.js", ".scribe/version.d.ts"];
54
+ // Bundle if configured
55
+ if (config.output.bundle) {
56
+ console.log("Bundling with Vite...");
57
+ await bundle(srcDir, outputDir);
58
+ // Copy type declarations to output dir
59
+ await copyFile(join(srcDir, "index.d.ts"), join(outputDir, "index.d.ts"));
60
+ await copyFile(join(srcDir, "version.d.ts"), join(outputDir, "version.d.ts"));
61
+ files.push("dist/codegen.js", "dist/index.js", "dist/version.js", "dist/index.d.ts", "dist/version.d.ts");
62
+ }
63
+ printSummary(mainPkg, vendorPkgs, config);
64
+ return { mainPkg, vendorPkgs, stdlibPkgs, outputDir, files };
65
+ }
66
+ function printSummary(mainPkg, vendorPkgs, config) {
67
+ console.log("");
68
+ console.log("Scribe complete:");
69
+ if (mainPkg) {
70
+ const templateCount = mainPkg.modules.reduce((acc, m) => acc + m.members.filter((t) => t.kind === "template").length, 0);
71
+ const interfaceCount = mainPkg.modules.reduce((acc, m) => acc + m.members.filter((t) => t.kind === "interface").length, 0);
72
+ const parts = [`${mainPkg.modules.length} modules`, `${templateCount} templates`];
73
+ if (interfaceCount > 0)
74
+ parts.push(`${interfaceCount} interfaces`);
75
+ console.log(` Main: ${mainPkg.name} (${parts.join(", ")})`);
76
+ }
77
+ for (const vendor of vendorPkgs) {
78
+ const templateCount = vendor.modules.reduce((acc, m) => acc + m.members.filter((t) => t.kind === "template").length, 0);
79
+ const interfaceCount = vendor.modules.reduce((acc, m) => acc + m.members.filter((t) => t.kind === "interface").length, 0);
80
+ const parts = [`${vendor.modules.length} modules`];
81
+ if (templateCount > 0)
82
+ parts.push(`${templateCount} templates`);
83
+ if (interfaceCount > 0)
84
+ parts.push(`${interfaceCount} interfaces`);
85
+ console.log(` Vendor: ${vendor.name} (${parts.join(", ")})`);
86
+ }
87
+ if (config.dryRun) {
88
+ console.log(" (dry run -- no files written)");
89
+ }
90
+ console.log("");
91
+ }
@@ -0,0 +1,9 @@
1
+ import type { AnalyzedPackage } from "../analyze.js";
2
+ import type { ResolvedConfig } from "../config.js";
3
+ /**
4
+ * Generate the versionedRegistry function and all registration calls.
5
+ *
6
+ * The generated function conforms to the VersionedRegistry type from
7
+ * @c7-digital/ledger (structurally, without importing it).
8
+ */
9
+ export declare function generateRegistry(mainPkg: AnalyzedPackage | undefined, vendorPkgs: AnalyzedPackage[], config: ResolvedConfig): string;