MCPcopy Create free account
hub / github.com/dmno-dev/bumpy / loadFormatter

Function loadFormatter

packages/bumpy/src/core/changelog.ts:164–223  ·  view source on GitHub ↗
(changelog: BumpyConfig['changelog'], rootDir: string)

Source from the content-addressed store, hash-verified

162 * Supports: "default", "./path/to/formatter.ts", or a module name.
163 */
164export async function loadFormatter(changelog: BumpyConfig['changelog'], rootDir: string): Promise<ChangelogFormatter> {
165 const [name, options] = Array.isArray(changelog) ? changelog : [changelog, {}];
166
167 // Built-in with options (e.g., ["github", { repo: "..." }])
168 if (name === 'github') {
169 const { createGithubFormatter } = await import('./changelog-github.ts');
170 return createGithubFormatter(options as import('./changelog-github.ts').GithubChangelogOptions);
171 }
172
173 // Built-in formatter (no options)
174 if (typeof name === 'string' && BUILTIN_FORMATTERS[name]) {
175 const builtin = BUILTIN_FORMATTERS[name];
176 if (typeof builtin === 'function' && builtin.length === 0) {
177 // Lazy-loaded formatter factory (like github)
178 return (builtin as () => Promise<ChangelogFormatter>)();
179 }
180 return builtin as ChangelogFormatter;
181 }
182
183 // Custom module
184 if (typeof name === 'string') {
185 try {
186 let modulePath: string;
187 if (name.startsWith('.')) {
188 // Relative path — resolve symlinks and verify it stays within the project root
189 modulePath = resolve(rootDir, name);
190 try {
191 modulePath = realpathSync(modulePath);
192 } catch {
193 // File doesn't exist yet — use the resolved path as-is
194 }
195 const rel = relative(realpathSync(rootDir), modulePath);
196 if (rel.startsWith('..') || resolve('/', rel) === resolve('/')) {
197 throw new Error(`Changelog formatter path "${name}" resolves outside the project root`);
198 }
199 } else {
200 // Bare module specifier (e.g. npm package name)
201 modulePath = name;
202 }
203 const mod = await import(modulePath);
204 // Support: export default fn, export const changelogFormatter = fn, or module is fn
205 const exported = mod.default || mod.changelogFormatter;
206 if (typeof exported === 'function') {
207 // If it takes options, call it as a factory; otherwise use it directly
208 // Heuristic: if the function returns a function, it's a factory
209 const result = exported(options);
210 if (typeof result === 'function') return result;
211 // If it returned a string/promise, it IS the formatter
212 return exported;
213 }
214 throw new Error(`Changelog module "${name}" does not export a function`);
215 } catch (err) {
216 log.warn(`Failed to load changelog formatter "${name}": ${err instanceof Error ? err.message : err}`);
217 log.warn('Falling back to default formatter');
218 return defaultFormatter;
219 }
220 }
221

Callers 3

changelog.test.tsFile · 0.90
runPublishFlowFunction · 0.90
applyReleasePlanFunction · 0.90

Calls 1

createGithubFormatterFunction · 0.85

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…