@libria/scaffold 0.2.2 → 0.3.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.
@@ -1 +1 @@
1
- 10987a3ef0ea968d116221eb59879c6f6a8ab34866f583e69a08a63d02c95e08
1
+ 2e6dfba476fdf1b53ab57bab7c8f2964b8b5cc592a2f63346b8b1677f1e28773
package/README.md CHANGED
@@ -262,7 +262,7 @@ templates/
262
262
  ### Step 2: Define Types (types.ts)
263
263
 
264
264
  ```typescript
265
- import { ScaffoldTemplatePluginOptions } from "@libria/scaffold";
265
+ import { ScaffoldTemplatePluginOptions } from "@libria/scaffold-core";
266
266
 
267
267
  export type MyTemplateOptions = ScaffoldTemplatePluginOptions & {
268
268
  packageName: string;
@@ -279,7 +279,7 @@ import { fileURLToPath } from 'url';
279
279
  import fs from 'fs-extra';
280
280
  import { input, confirm } from '@inquirer/prompts';
281
281
  import { definePlugin } from '@libria/plugin-loader';
282
- import { SCAFFOLD_TEMPLATE_PLUGIN_TYPE, ScaffoldTemplatePlugin } from '@libria/scaffold';
282
+ import { SCAFFOLD_TEMPLATE_PLUGIN_TYPE, ScaffoldTemplatePlugin } from '@libria/scaffold-core';
283
283
  import { MyTemplateOptions } from './types';
284
284
 
285
285
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -389,20 +389,25 @@ This compiles your template plugins to the `dist/templates` directory.
389
389
 
390
390
  ## Development
391
391
 
392
+ This package is part of the [LibriaForge Scaffold monorepo](../README.md). From the repo root:
393
+
392
394
  ```bash
393
- # Install dependencies
395
+ # Install all dependencies
394
396
  npm install
395
397
 
396
- # Build the project
398
+ # Build all packages
397
399
  npm run build
398
400
 
399
- # Build templates
400
- npm run build:templates
401
+ # Run all tests
402
+ npm run test
403
+ ```
401
404
 
402
- # Run tests
403
- npm test
405
+ Or work on the CLI package directly:
404
406
 
405
- # Lint and format
407
+ ```bash
408
+ cd cli
409
+ npm run build
410
+ npm test
406
411
  npm run clean
407
412
  ```
408
413
 
package/dist/cli/cli.mjs CHANGED
@@ -3,10 +3,10 @@ import { fileURLToPath } from "url";
3
3
  import { PluginManager } from "@libria/plugin-loader";
4
4
  import { InteractiveCommand, Option } from "interactive-commander";
5
5
  import fs from "fs/promises";
6
- import "fs-extra";
7
6
  import { execFile } from "node:child_process";
8
7
  import { promisify } from "node:util";
9
8
  import * as readline from "node:readline";
9
+ import { SCAFFOLD_TEMPLATE_PLUGIN_TYPE } from "@libria/scaffold-core";
10
10
 
11
11
  //#region src/config.ts
12
12
  const CONFIG_FILENAME = ".lbscaffold";
@@ -273,10 +273,6 @@ async function registerConfigCommand(program) {
273
273
  return configCommand;
274
274
  }
275
275
 
276
- //#endregion
277
- //#region src/core/types.ts
278
- const SCAFFOLD_TEMPLATE_PLUGIN_TYPE = "scaffold-template";
279
-
280
276
  //#endregion
281
277
  //#region src/commands/register-new.command.ts
282
278
  let rl = null;
@@ -426,7 +422,6 @@ const packageNames = await listPackages();
426
422
  const packagePaths = await Promise.all(packageNames.map(async (name) => {
427
423
  return await resolvePackageDir(name);
428
424
  }));
429
- console.log(packagePaths);
430
425
  const pluginManager = new PluginManager();
431
426
  await pluginManager.loadPlugins([
432
427
  PLUGINS_FOLDER,
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":[],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts","../../src/commands/register-config.command.ts","../../src/core/types.ts","../../src/commands/register-new.command.ts","../../src/cli.ts"],"sourcesContent":["import fs from 'fs/promises';\nimport path from 'path';\n\nexport interface LbScaffoldConfig {\n plugins?: string[];\n packages?: string[];\n}\n\nconst CONFIG_FILENAME = '.lbscaffold';\n\n/**\n * Find the config file by searching up the directory tree\n */\nexport async function findConfigPath(startDir: string = process.cwd()): Promise<string | null> {\n let currentDir = startDir;\n\n while (true) {\n const configPath = path.join(currentDir, CONFIG_FILENAME);\n try {\n await fs.access(configPath);\n return configPath;\n } catch {\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n // Reached root\n return null;\n }\n currentDir = parentDir;\n }\n }\n}\n\n/**\n * Get the default config path in the current directory\n */\nexport function getDefaultConfigPath(): string {\n return path.join(process.cwd(), CONFIG_FILENAME);\n}\n\n/**\n * Load the config file\n */\nexport async function loadConfig(configPath?: string): Promise<LbScaffoldConfig> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n return {};\n }\n\n try {\n const content = await fs.readFile(resolvedPath, 'utf-8');\n return JSON.parse(content) as LbScaffoldConfig;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw new Error(`Failed to load config from ${resolvedPath}: ${(error as Error).message}`);\n }\n}\n\n/**\n * Save the config file\n */\nexport async function saveConfig(config: LbScaffoldConfig, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n await fs.writeFile(resolvedPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Initialize a new config file\n */\nexport async function initConfig(configPath?: string): Promise<string> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n\n try {\n await fs.access(resolvedPath);\n throw new Error(`Config file already exists at ${resolvedPath}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n\n const defaultConfig: LbScaffoldConfig = {\n plugins: ['./plugins/**'],\n packages: [],\n };\n\n await saveConfig(defaultConfig, resolvedPath);\n return resolvedPath;\n}\n\n/**\n * Add a plugin glob pattern to the config\n */\nexport async function addPluginGlob(glob: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.plugins) {\n config.plugins = [];\n }\n\n if (config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' already exists in config`);\n }\n\n config.plugins.push(glob);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove a plugin glob pattern from the config\n */\nexport async function removePluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.plugins || !config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' not found in config`);\n }\n\n config.plugins = config.plugins.filter(p => p !== glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all plugin glob patterns in the config\n */\nexport async function listPluginGlobs(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.plugins ?? [];\n}\n\n/**\n * Get absolute plugin paths from config globs\n */\nexport async function getPluginPaths(configPath?: string): Promise<string[]> {\n const resolvedConfigPath = configPath ?? (await findConfigPath());\n\n if (!resolvedConfigPath) {\n return [];\n }\n\n const config = await loadConfig(resolvedConfigPath);\n const configDir = path.dirname(resolvedConfigPath);\n\n return (config.plugins ?? []).map(glob => {\n // If glob is absolute, use as-is; otherwise resolve relative to config file\n if (path.isAbsolute(glob)) {\n return glob.replace(/\\\\/g, '/');\n }\n return path.resolve(configDir, glob).replace(/\\\\/g, '/');\n });\n}\n\n/**\n * Add an npm package name to the config\n */\nexport async function addPackage(packageName: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.packages) {\n config.packages = [];\n }\n\n if (config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' already exists in config`);\n }\n\n config.packages.push(packageName);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove an npm package name from the config\n */\nexport async function removePackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.packages || !config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' not found in config`);\n }\n\n config.packages = config.packages.filter(p => p !== packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all npm package names in the config\n */\nexport async function listPackages(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.packages ?? [];\n}\n","import fs from 'fs/promises';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport path from 'path';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Resolve an npm package name to its installed root directory.\n * Tries local node_modules first (relative to cwd), then global.\n */\nexport async function resolvePackageDir(packageName: string): Promise<string> {\n // Strategy 1: resolve from local node_modules via cwd\n const localCandidate = path.join(process.cwd(), 'node_modules', packageName);\n try {\n await fs.access(path.join(localCandidate, 'package.json'));\n return localCandidate;\n } catch {\n // Not found locally, try global\n }\n\n // Strategy 2: resolve from global node_modules\n const globalDir = await getGlobalNodeModulesDir();\n if (globalDir) {\n const globalCandidate = path.join(globalDir, packageName);\n try {\n await fs.access(path.join(globalCandidate, 'package.json'));\n return globalCandidate;\n } catch {\n // Not found globally either\n }\n }\n\n throw new Error(\n `Package '${packageName}' not found. ` +\n `Install it locally (npm install ${packageName}) or globally (npm install -g ${packageName}).`\n );\n}\n\n/**\n * Get the global node_modules directory using npm root -g.\n */\nasync function getGlobalNodeModulesDir(): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync('npm', ['root', '-g'], { encoding: 'utf-8' });\n const dir = stdout.trim();\n await fs.access(dir);\n return dir;\n } catch {\n return null;\n }\n}\n","import { InteractiveCommand } from 'interactive-commander';\n\nimport {\n addPackage,\n addPluginGlob,\n findConfigPath,\n initConfig,\n listPackages,\n listPluginGlobs,\n loadConfig,\n removePackage,\n removePluginGlob,\n} from '../config';\nimport { resolvePackageDir } from '../utils';\n\nexport async function registerConfigCommand(\n program: InteractiveCommand\n): Promise<InteractiveCommand> {\n const configCommand = program.command('config').description('Manage lb-scaffold configuration');\n\n configCommand\n .command('init')\n .description('Initialize a new .lbscaffold config file in the current directory')\n .action(async () => {\n try {\n const configPath = await initConfig();\n console.log(`Created config file: ${configPath}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('add <glob>')\n .description('Add a plugin glob pattern to the config')\n .action(async (glob: string) => {\n try {\n await addPluginGlob(glob);\n console.log(`Added plugin pattern: ${glob}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('remove <glob>')\n .description('Remove a plugin glob pattern from the config')\n .action(async (glob: string) => {\n try {\n await removePluginGlob(glob);\n console.log(`Removed plugin pattern: ${glob}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('list')\n .description('List all plugin patterns and packages in the config')\n .action(async () => {\n const configPath = await findConfigPath();\n if (!configPath) {\n console.log('No .lbscaffold config file found.');\n console.log('Run \"lb-scaffold config init\" to create one.');\n return;\n }\n\n console.log(`Config file: ${configPath}\\n`);\n\n const globs = await listPluginGlobs();\n if (globs.length === 0) {\n console.log('No plugin patterns configured.');\n } else {\n console.log('Plugin patterns:');\n for (const glob of globs) {\n console.log(` - ${glob}`);\n }\n }\n\n const packages = await listPackages();\n if (packages.length > 0) {\n console.log('\\nPackages:');\n for (const pkg of packages) {\n console.log(` - ${pkg}`);\n }\n }\n });\n\n configCommand\n .command('show')\n .description('Show the full config file contents')\n .action(async () => {\n const configPath = await findConfigPath();\n if (!configPath) {\n console.log('No .lbscaffold config file found.');\n console.log('Run \"lb-scaffold config init\" to create one.');\n return;\n }\n\n console.log(`Config file: ${configPath}\\n`);\n const config = await loadConfig(configPath);\n console.log(JSON.stringify(config, null, 2));\n });\n\n configCommand\n .command('add-package <name>')\n .description('Add an npm package as a plugin source')\n .action(async (name: string) => {\n try {\n await resolvePackageDir(name);\n await addPackage(name);\n console.log(`Added package: ${name}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('remove-package <name>')\n .description('Remove an npm package from plugin sources')\n .action(async (name: string) => {\n try {\n await removePackage(name);\n console.log(`Removed package: ${name}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('list-packages')\n .description('List all npm packages configured as plugin sources')\n .action(async () => {\n const configPath = await findConfigPath();\n if (!configPath) {\n console.log('No .lbscaffold config file found.');\n console.log('Run \"lb-scaffold config init\" to create one.');\n return;\n }\n\n const packages = await listPackages();\n if (packages.length === 0) {\n console.log('No packages configured.');\n } else {\n console.log('Packages:');\n for (const pkg of packages) {\n console.log(` - ${pkg}`);\n }\n }\n });\n\n return configCommand;\n}\n","export const SCAFFOLD_TEMPLATE_PLUGIN_TYPE = 'scaffold-template';\n\nexport type ScaffoldTemplatePluginOption<TValue = string | boolean | number> = {\n readonly flags: string; // ex: --git-init\n readonly required?: boolean;\n readonly description: string;\n readonly defaultValue?: TValue | TValue[];\n readonly choices?: TValue[];\n};\n\nexport type ResolvedOptions<TOpt extends object> = {\n [k in keyof TOpt]: TOpt[k] extends ScaffoldTemplatePluginOption<infer TValue> ? TValue : never;\n};\n\nexport type ExecuteOptions<TOpt extends object> = ScaffoldTemplatePluginOptions & {\n [k in keyof TOpt]: TOpt[k] extends ScaffoldTemplatePluginOption<infer TValue> ? TValue : never;\n};\n\nexport interface ScaffoldTemplatePlugin<TOpt extends object = object> {\n readonly argument: string;\n\n getOptions(options: ScaffoldTemplatePluginOptions & Partial<ResolvedOptions<TOpt>>): Promise<\n Partial<{\n [k in keyof TOpt]: ScaffoldTemplatePluginOption;\n }>\n >;\n\n execute(options: ExecuteOptions<TOpt>): Promise<void>;\n}\n\nexport type ScaffoldTemplatePluginOptions = {\n name: string;\n dryRun?: boolean;\n force?: boolean;\n};\n","import * as readline from 'node:readline';\n\nimport { PluginManager } from '@libria/plugin-loader';\nimport { Command, InteractiveCommand, Option } from 'interactive-commander';\n\nimport {\n ScaffoldTemplatePlugin,\n SCAFFOLD_TEMPLATE_PLUGIN_TYPE,\n ScaffoldTemplatePluginOption,\n ScaffoldTemplatePluginOptions,\n} from '../core';\n\n// ── Prompting helpers (readline-based, zero dependencies) ────────────────────\n\nlet rl: readline.Interface | null = null;\n\nfunction getRL(): readline.Interface {\n if (!rl) rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n return rl;\n}\n\nfunction closeRL(): void {\n rl?.close();\n rl = null;\n}\n\nfunction ask(question: string): Promise<string> {\n return new Promise(resolve => getRL().question(question, resolve));\n}\n\nasync function promptSelect(\n message: string,\n choices: unknown[],\n defaultValue?: unknown\n): Promise<string> {\n const items = choices.map(String);\n console.log(`\\n ${message}`);\n items.forEach((c, i) => {\n const marker = c === String(defaultValue) ? ' (default)' : '';\n console.log(` ${i + 1}) ${c}${marker}`);\n });\n const answer = await ask(` Choice [${defaultValue ?? items[0]}]: `);\n if (!answer.trim()) return String(defaultValue ?? items[0]);\n const idx = parseInt(answer, 10);\n if (idx >= 1 && idx <= items.length) return items[idx - 1];\n if (items.includes(answer.trim())) return answer.trim();\n return String(defaultValue ?? items[0]);\n}\n\nasync function promptConfirm(message: string, defaultValue?: unknown): Promise<boolean> {\n const def = defaultValue === false ? 'N' : 'Y';\n const answer = await ask(` ${message} (Y/n) [${def}]: `);\n if (!answer.trim()) return defaultValue !== false;\n return answer.trim().toLowerCase().startsWith('y');\n}\n\nasync function promptInput(message: string, defaultValue?: unknown): Promise<string> {\n const suffix = defaultValue !== undefined ? ` [${defaultValue}]` : '';\n const answer = await ask(` ${message}${suffix}: `);\n return answer.trim() || String(defaultValue ?? '');\n}\n\n// ── Option type detection ────────────────────────────────────────────────────\n\nfunction isBooleanFlag(opt: ScaffoldTemplatePluginOption): boolean {\n return !opt.flags.includes('<') && !opt.choices?.length;\n}\n\n// ── Prompt for a single option ───────────────────────────────────────────────\n\nasync function promptForOption(key: string, def: ScaffoldTemplatePluginOption): Promise<unknown> {\n if (def.choices?.length) {\n return promptSelect(def.description, def.choices, def.defaultValue);\n }\n if (isBooleanFlag(def)) {\n return promptConfirm(def.description, def.defaultValue);\n }\n return promptInput(def.description, def.defaultValue);\n}\n\n// ── Iterative option resolution ──────────────────────────────────────────────\n\n/**\n * Resolves plugin options iteratively:\n * 1. Call getOptions(collected) to get currently-relevant options\n * 2. Prompt for any unanswered options (or use CLI-provided values)\n * 3. If new options appeared, repeat — the plugin may reveal more\n * options based on the newly-collected answers\n * 4. Stop when no new unanswered options appear\n */\nasync function resolveOptions(\n plugin: ScaffoldTemplatePlugin,\n collected: Record<string, unknown>,\n cliOpts: Record<string, unknown>\n): Promise<void> {\n while (true) {\n const optionDefs = await plugin.getOptions(\n collected as ScaffoldTemplatePluginOptions & Partial<Record<string, unknown>>\n );\n\n let hasNewOptions = false;\n\n for (const [key, def] of Object.entries(optionDefs)) {\n if (def === undefined) continue;\n if (collected[key] !== undefined) continue;\n\n hasNewOptions = true;\n\n // Use CLI-provided value if available, otherwise prompt\n if (cliOpts[key] !== undefined) {\n collected[key] = cliOpts[key];\n } else {\n collected[key] = await promptForOption(key, def);\n }\n }\n\n if (!hasNewOptions) break;\n }\n}\n\n// ── Argv pre-parsing ─────────────────────────────────────────────────────────\n/**\n * Pre-parse process.argv to extract values for a set of option definitions.\n * This is a lightweight scan — no full Commander parse — so we can call\n * getOptions() with the values before Commander registers anything.\n */\nfunction preParseArgv(\n optionDefs: Record<string, ScaffoldTemplatePluginOption>\n): Record<string, string> {\n const args = process.argv.slice(2);\n const result: Record<string, string> = {};\n\n for (const [key, def] of Object.entries(optionDefs)) {\n if (def === undefined) continue;\n\n // Extract the --flag-name from the flags string\n const flagMatch = def.flags.match(/--([a-z][a-z-]*)/i);\n if (!flagMatch) continue;\n const flagName = `--${flagMatch[1]}`;\n\n // Check for --flag value or --flag=value\n const eqArg = args.find(a => a.startsWith(`${flagName}=`));\n if (eqArg) {\n result[key] = eqArg.split('=')[1];\n continue;\n }\n\n const idx = args.indexOf(flagName);\n if (idx !== -1 && idx + 1 < args.length) {\n // Boolean flags (no <value> in flags string) don't consume next arg\n if (!def.flags.includes('<')) continue;\n result[key] = args[idx + 1];\n }\n }\n\n return result;\n}\n\n// ── Commander option registration ────────────────────────────────────────────\n\nfunction registerOption(cmd: Command, def: ScaffoldTemplatePluginOption): void {\n const cmdOption = new Option(def.flags, def.description);\n\n if (def.defaultValue !== undefined) {\n cmdOption.default(def.defaultValue);\n }\n if (def.choices?.length) {\n cmdOption.choices(def.choices.map(String));\n }\n if (def.required) {\n cmdOption.makeOptionMandatory();\n }\n\n cmd.addOption(cmdOption);\n}\n\nexport async function registerNewCommand(\n program: InteractiveCommand,\n pluginManager: PluginManager\n): Promise<Command> {\n const newCmd = program.command('new').description('Create a new project from a template');\n\n const templates = pluginManager.getPluginsByType(SCAFFOLD_TEMPLATE_PLUGIN_TYPE);\n\n for (const meta of templates) {\n const plugin = pluginManager.getPlugin<ScaffoldTemplatePlugin>(meta.id);\n\n const sub = newCmd\n .command(plugin.argument)\n .description(`Create a new ${plugin.argument} project`)\n .argument('<name>', 'Project name')\n .option('--dry-run', 'Simulate without writing files', false)\n .option('--force', 'Overwrite existing files', false)\n .allowUnknownOption(true);\n\n // Iteratively resolve options from argv so --help shows the right set.\n // Phase 1: get initial options, pre-parse their values from argv\n // Phase N: feed values back into getOptions until options stabilize\n let optionDefs = await plugin.getOptions({ name: '' } as ScaffoldTemplatePluginOptions &\n Partial<Record<string, unknown>>);\n let preCollected: Record<string, unknown> = { name: '' };\n let previousKeys = new Set<string>();\n\n while (true) {\n const currentKeys = new Set(Object.keys(optionDefs));\n const newKeys = [...currentKeys].filter(k => !previousKeys.has(k));\n if (newKeys.length === 0) break;\n\n // Pre-parse any new option values from argv\n const parsed = preParseArgv(optionDefs as Record<string, ScaffoldTemplatePluginOption>);\n preCollected = { ...preCollected, ...parsed };\n previousKeys = currentKeys;\n\n // Ask plugin for options again with the parsed values\n optionDefs = await plugin.getOptions(\n preCollected as ScaffoldTemplatePluginOptions & Partial<Record<string, unknown>>\n );\n }\n\n // Register the fully-resolved options with Commander\n for (const [, def] of Object.entries(optionDefs)) {\n if (def === undefined) continue;\n registerOption(sub, def);\n }\n\n sub.action(async (name: string, cliOpts: Record<string, unknown>) => {\n const collected: Record<string, unknown> = {\n name,\n dryRun: cliOpts.dryRun,\n force: cliOpts.force,\n };\n\n // Iteratively resolve all options (prompt for missing ones)\n await resolveOptions(plugin, collected, cliOpts);\n\n closeRL();\n await plugin.execute(\n collected as ScaffoldTemplatePluginOptions & Record<string, unknown>\n );\n });\n }\n\n return newCmd;\n}\n","import path from 'path';\nimport { fileURLToPath } from 'url';\n\nimport { PluginManager } from '@libria/plugin-loader';\nimport { InteractiveCommand, Option } from 'interactive-commander';\n\nimport { registerConfigCommand, registerNewCommand } from './commands';\nimport { getPluginPaths, listPackages } from './config';\nimport { resolvePackageDir } from './utils';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\nconst PLUGINS_FOLDER = path.resolve(__dirname, '../templates').replace(/\\\\/g, '/');\n\n// Load user plugins from config\nconst userPluginPaths = await getPluginPaths();\n\n// Load plugins from npm packages\nconst packageNames = await listPackages();\n\nconst packagePaths = await Promise.all(\n packageNames.map(async name => {\n const dir = await resolvePackageDir(name);\n return dir;\n })\n);\n\nconsole.log(packagePaths);\nconst pluginManager = new PluginManager();\nawait pluginManager.loadPlugins([PLUGINS_FOLDER, ...userPluginPaths, ...packagePaths]);\n\nconst program = new InteractiveCommand();\nprogram.name('lb-scaffold').description('Scaffold new projects from templates');\n\nawait registerNewCommand(program, pluginManager);\nawait registerConfigCommand(program);\n\n// Enable interactive mode by default\nprogram.addOption(new Option('-i, --interactive', 'Run in interactive mode').default(true));\n\nawait program.interactive().parseAsync();\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.mjs","names":[],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts","../../src/commands/register-config.command.ts","../../src/commands/register-new.command.ts","../../src/cli.ts"],"sourcesContent":["import fs from 'fs/promises';\nimport path from 'path';\n\nexport interface LbScaffoldConfig {\n plugins?: string[];\n packages?: string[];\n}\n\nconst CONFIG_FILENAME = '.lbscaffold';\n\n/**\n * Find the config file by searching up the directory tree\n */\nexport async function findConfigPath(startDir: string = process.cwd()): Promise<string | null> {\n let currentDir = startDir;\n\n while (true) {\n const configPath = path.join(currentDir, CONFIG_FILENAME);\n try {\n await fs.access(configPath);\n return configPath;\n } catch {\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n // Reached root\n return null;\n }\n currentDir = parentDir;\n }\n }\n}\n\n/**\n * Get the default config path in the current directory\n */\nexport function getDefaultConfigPath(): string {\n return path.join(process.cwd(), CONFIG_FILENAME);\n}\n\n/**\n * Load the config file\n */\nexport async function loadConfig(configPath?: string): Promise<LbScaffoldConfig> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n return {};\n }\n\n try {\n const content = await fs.readFile(resolvedPath, 'utf-8');\n return JSON.parse(content) as LbScaffoldConfig;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw new Error(`Failed to load config from ${resolvedPath}: ${(error as Error).message}`);\n }\n}\n\n/**\n * Save the config file\n */\nexport async function saveConfig(config: LbScaffoldConfig, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n await fs.writeFile(resolvedPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Initialize a new config file\n */\nexport async function initConfig(configPath?: string): Promise<string> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n\n try {\n await fs.access(resolvedPath);\n throw new Error(`Config file already exists at ${resolvedPath}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n\n const defaultConfig: LbScaffoldConfig = {\n plugins: ['./plugins/**'],\n packages: [],\n };\n\n await saveConfig(defaultConfig, resolvedPath);\n return resolvedPath;\n}\n\n/**\n * Add a plugin glob pattern to the config\n */\nexport async function addPluginGlob(glob: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.plugins) {\n config.plugins = [];\n }\n\n if (config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' already exists in config`);\n }\n\n config.plugins.push(glob);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove a plugin glob pattern from the config\n */\nexport async function removePluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.plugins || !config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' not found in config`);\n }\n\n config.plugins = config.plugins.filter(p => p !== glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all plugin glob patterns in the config\n */\nexport async function listPluginGlobs(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.plugins ?? [];\n}\n\n/**\n * Get absolute plugin paths from config globs\n */\nexport async function getPluginPaths(configPath?: string): Promise<string[]> {\n const resolvedConfigPath = configPath ?? (await findConfigPath());\n\n if (!resolvedConfigPath) {\n return [];\n }\n\n const config = await loadConfig(resolvedConfigPath);\n const configDir = path.dirname(resolvedConfigPath);\n\n return (config.plugins ?? []).map(glob => {\n // If glob is absolute, use as-is; otherwise resolve relative to config file\n if (path.isAbsolute(glob)) {\n return glob.replace(/\\\\/g, '/');\n }\n return path.resolve(configDir, glob).replace(/\\\\/g, '/');\n });\n}\n\n/**\n * Add an npm package name to the config\n */\nexport async function addPackage(packageName: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.packages) {\n config.packages = [];\n }\n\n if (config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' already exists in config`);\n }\n\n config.packages.push(packageName);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove an npm package name from the config\n */\nexport async function removePackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.packages || !config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' not found in config`);\n }\n\n config.packages = config.packages.filter(p => p !== packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all npm package names in the config\n */\nexport async function listPackages(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.packages ?? [];\n}\n","import fs from 'fs/promises';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport path from 'path';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Resolve an npm package name to its installed root directory.\n * Tries local node_modules first (relative to cwd), then global.\n */\nexport async function resolvePackageDir(packageName: string): Promise<string> {\n // Strategy 1: resolve from local node_modules via cwd\n const localCandidate = path.join(process.cwd(), 'node_modules', packageName);\n try {\n await fs.access(path.join(localCandidate, 'package.json'));\n return localCandidate;\n } catch {\n // Not found locally, try global\n }\n\n // Strategy 2: resolve from global node_modules\n const globalDir = await getGlobalNodeModulesDir();\n if (globalDir) {\n const globalCandidate = path.join(globalDir, packageName);\n try {\n await fs.access(path.join(globalCandidate, 'package.json'));\n return globalCandidate;\n } catch {\n // Not found globally either\n }\n }\n\n throw new Error(\n `Package '${packageName}' not found. ` +\n `Install it locally (npm install ${packageName}) or globally (npm install -g ${packageName}).`\n );\n}\n\n/**\n * Get the global node_modules directory using npm root -g.\n */\nasync function getGlobalNodeModulesDir(): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync('npm', ['root', '-g'], { encoding: 'utf-8' });\n const dir = stdout.trim();\n await fs.access(dir);\n return dir;\n } catch {\n return null;\n }\n}\n","import { InteractiveCommand } from 'interactive-commander';\n\nimport {\n addPackage,\n addPluginGlob,\n findConfigPath,\n initConfig,\n listPackages,\n listPluginGlobs,\n loadConfig,\n removePackage,\n removePluginGlob,\n} from '../config';\nimport { resolvePackageDir } from '../utils';\n\nexport async function registerConfigCommand(\n program: InteractiveCommand\n): Promise<InteractiveCommand> {\n const configCommand = program.command('config').description('Manage lb-scaffold configuration');\n\n configCommand\n .command('init')\n .description('Initialize a new .lbscaffold config file in the current directory')\n .action(async () => {\n try {\n const configPath = await initConfig();\n console.log(`Created config file: ${configPath}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('add <glob>')\n .description('Add a plugin glob pattern to the config')\n .action(async (glob: string) => {\n try {\n await addPluginGlob(glob);\n console.log(`Added plugin pattern: ${glob}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('remove <glob>')\n .description('Remove a plugin glob pattern from the config')\n .action(async (glob: string) => {\n try {\n await removePluginGlob(glob);\n console.log(`Removed plugin pattern: ${glob}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('list')\n .description('List all plugin patterns and packages in the config')\n .action(async () => {\n const configPath = await findConfigPath();\n if (!configPath) {\n console.log('No .lbscaffold config file found.');\n console.log('Run \"lb-scaffold config init\" to create one.');\n return;\n }\n\n console.log(`Config file: ${configPath}\\n`);\n\n const globs = await listPluginGlobs();\n if (globs.length === 0) {\n console.log('No plugin patterns configured.');\n } else {\n console.log('Plugin patterns:');\n for (const glob of globs) {\n console.log(` - ${glob}`);\n }\n }\n\n const packages = await listPackages();\n if (packages.length > 0) {\n console.log('\\nPackages:');\n for (const pkg of packages) {\n console.log(` - ${pkg}`);\n }\n }\n });\n\n configCommand\n .command('show')\n .description('Show the full config file contents')\n .action(async () => {\n const configPath = await findConfigPath();\n if (!configPath) {\n console.log('No .lbscaffold config file found.');\n console.log('Run \"lb-scaffold config init\" to create one.');\n return;\n }\n\n console.log(`Config file: ${configPath}\\n`);\n const config = await loadConfig(configPath);\n console.log(JSON.stringify(config, null, 2));\n });\n\n configCommand\n .command('add-package <name>')\n .description('Add an npm package as a plugin source')\n .action(async (name: string) => {\n try {\n await resolvePackageDir(name);\n await addPackage(name);\n console.log(`Added package: ${name}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('remove-package <name>')\n .description('Remove an npm package from plugin sources')\n .action(async (name: string) => {\n try {\n await removePackage(name);\n console.log(`Removed package: ${name}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('list-packages')\n .description('List all npm packages configured as plugin sources')\n .action(async () => {\n const configPath = await findConfigPath();\n if (!configPath) {\n console.log('No .lbscaffold config file found.');\n console.log('Run \"lb-scaffold config init\" to create one.');\n return;\n }\n\n const packages = await listPackages();\n if (packages.length === 0) {\n console.log('No packages configured.');\n } else {\n console.log('Packages:');\n for (const pkg of packages) {\n console.log(` - ${pkg}`);\n }\n }\n });\n\n return configCommand;\n}\n","import * as readline from 'node:readline';\n\nimport { PluginManager } from '@libria/plugin-loader';\nimport { Command, InteractiveCommand, Option } from 'interactive-commander';\n\nimport {\n ScaffoldTemplatePlugin,\n SCAFFOLD_TEMPLATE_PLUGIN_TYPE,\n ScaffoldTemplatePluginOption,\n ScaffoldTemplatePluginOptions,\n} from '@libria/scaffold-core';\n\n// ── Prompting helpers (readline-based, zero dependencies) ────────────────────\n\nlet rl: readline.Interface | null = null;\n\nfunction getRL(): readline.Interface {\n if (!rl) rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n return rl;\n}\n\nfunction closeRL(): void {\n rl?.close();\n rl = null;\n}\n\nfunction ask(question: string): Promise<string> {\n return new Promise(resolve => getRL().question(question, resolve));\n}\n\nasync function promptSelect(\n message: string,\n choices: unknown[],\n defaultValue?: unknown\n): Promise<string> {\n const items = choices.map(String);\n console.log(`\\n ${message}`);\n items.forEach((c, i) => {\n const marker = c === String(defaultValue) ? ' (default)' : '';\n console.log(` ${i + 1}) ${c}${marker}`);\n });\n const answer = await ask(` Choice [${defaultValue ?? items[0]}]: `);\n if (!answer.trim()) return String(defaultValue ?? items[0]);\n const idx = parseInt(answer, 10);\n if (idx >= 1 && idx <= items.length) return items[idx - 1];\n if (items.includes(answer.trim())) return answer.trim();\n return String(defaultValue ?? items[0]);\n}\n\nasync function promptConfirm(message: string, defaultValue?: unknown): Promise<boolean> {\n const def = defaultValue === false ? 'N' : 'Y';\n const answer = await ask(` ${message} (Y/n) [${def}]: `);\n if (!answer.trim()) return defaultValue !== false;\n return answer.trim().toLowerCase().startsWith('y');\n}\n\nasync function promptInput(message: string, defaultValue?: unknown): Promise<string> {\n const suffix = defaultValue !== undefined ? ` [${defaultValue}]` : '';\n const answer = await ask(` ${message}${suffix}: `);\n return answer.trim() || String(defaultValue ?? '');\n}\n\n// ── Option type detection ────────────────────────────────────────────────────\n\nfunction isBooleanFlag(opt: ScaffoldTemplatePluginOption): boolean {\n return !opt.flags.includes('<') && !opt.choices?.length;\n}\n\n// ── Prompt for a single option ───────────────────────────────────────────────\n\nasync function promptForOption(key: string, def: ScaffoldTemplatePluginOption): Promise<unknown> {\n if (def.choices?.length) {\n return promptSelect(def.description, def.choices, def.defaultValue);\n }\n if (isBooleanFlag(def)) {\n return promptConfirm(def.description, def.defaultValue);\n }\n return promptInput(def.description, def.defaultValue);\n}\n\n// ── Iterative option resolution ──────────────────────────────────────────────\n\n/**\n * Resolves plugin options iteratively:\n * 1. Call getOptions(collected) to get currently-relevant options\n * 2. Prompt for any unanswered options (or use CLI-provided values)\n * 3. If new options appeared, repeat — the plugin may reveal more\n * options based on the newly-collected answers\n * 4. Stop when no new unanswered options appear\n */\nasync function resolveOptions(\n plugin: ScaffoldTemplatePlugin,\n collected: Record<string, unknown>,\n cliOpts: Record<string, unknown>\n): Promise<void> {\n while (true) {\n const optionDefs = await plugin.getOptions(\n collected as ScaffoldTemplatePluginOptions & Partial<Record<string, unknown>>\n );\n\n let hasNewOptions = false;\n\n for (const [key, def] of Object.entries(optionDefs)) {\n if (def === undefined) continue;\n if (collected[key] !== undefined) continue;\n\n hasNewOptions = true;\n\n // Use CLI-provided value if available, otherwise prompt\n if (cliOpts[key] !== undefined) {\n collected[key] = cliOpts[key];\n } else {\n collected[key] = await promptForOption(key, def);\n }\n }\n\n if (!hasNewOptions) break;\n }\n}\n\n// ── Argv pre-parsing ─────────────────────────────────────────────────────────\n/**\n * Pre-parse process.argv to extract values for a set of option definitions.\n * This is a lightweight scan — no full Commander parse — so we can call\n * getOptions() with the values before Commander registers anything.\n */\nfunction preParseArgv(\n optionDefs: Record<string, ScaffoldTemplatePluginOption>\n): Record<string, string> {\n const args = process.argv.slice(2);\n const result: Record<string, string> = {};\n\n for (const [key, def] of Object.entries(optionDefs)) {\n if (def === undefined) continue;\n\n // Extract the --flag-name from the flags string\n const flagMatch = def.flags.match(/--([a-z][a-z-]*)/i);\n if (!flagMatch) continue;\n const flagName = `--${flagMatch[1]}`;\n\n // Check for --flag value or --flag=value\n const eqArg = args.find(a => a.startsWith(`${flagName}=`));\n if (eqArg) {\n result[key] = eqArg.split('=')[1];\n continue;\n }\n\n const idx = args.indexOf(flagName);\n if (idx !== -1 && idx + 1 < args.length) {\n // Boolean flags (no <value> in flags string) don't consume next arg\n if (!def.flags.includes('<')) continue;\n result[key] = args[idx + 1];\n }\n }\n\n return result;\n}\n\n// ── Commander option registration ────────────────────────────────────────────\n\nfunction registerOption(cmd: Command, def: ScaffoldTemplatePluginOption): void {\n const cmdOption = new Option(def.flags, def.description);\n\n if (def.defaultValue !== undefined) {\n cmdOption.default(def.defaultValue);\n }\n if (def.choices?.length) {\n cmdOption.choices(def.choices.map(String));\n }\n if (def.required) {\n cmdOption.makeOptionMandatory();\n }\n\n cmd.addOption(cmdOption);\n}\n\nexport async function registerNewCommand(\n program: InteractiveCommand,\n pluginManager: PluginManager\n): Promise<Command> {\n const newCmd = program.command('new').description('Create a new project from a template');\n\n const templates = pluginManager.getPluginsByType(SCAFFOLD_TEMPLATE_PLUGIN_TYPE);\n\n for (const meta of templates) {\n const plugin = pluginManager.getPlugin<ScaffoldTemplatePlugin>(meta.id);\n\n const sub = newCmd\n .command(plugin.argument)\n .description(`Create a new ${plugin.argument} project`)\n .argument('<name>', 'Project name')\n .option('--dry-run', 'Simulate without writing files', false)\n .option('--force', 'Overwrite existing files', false)\n .allowUnknownOption(true);\n\n // Iteratively resolve options from argv so --help shows the right set.\n // Phase 1: get initial options, pre-parse their values from argv\n // Phase N: feed values back into getOptions until options stabilize\n let optionDefs = await plugin.getOptions({ name: '' } as ScaffoldTemplatePluginOptions &\n Partial<Record<string, unknown>>);\n let preCollected: Record<string, unknown> = { name: '' };\n let previousKeys = new Set<string>();\n\n while (true) {\n const currentKeys = new Set(Object.keys(optionDefs));\n const newKeys = [...currentKeys].filter(k => !previousKeys.has(k));\n if (newKeys.length === 0) break;\n\n // Pre-parse any new option values from argv\n const parsed = preParseArgv(optionDefs as Record<string, ScaffoldTemplatePluginOption>);\n preCollected = { ...preCollected, ...parsed };\n previousKeys = currentKeys;\n\n // Ask plugin for options again with the parsed values\n optionDefs = await plugin.getOptions(\n preCollected as ScaffoldTemplatePluginOptions & Partial<Record<string, unknown>>\n );\n }\n\n // Register the fully-resolved options with Commander\n for (const [, def] of Object.entries(optionDefs)) {\n if (def === undefined) continue;\n registerOption(sub, def);\n }\n\n sub.action(async (name: string, cliOpts: Record<string, unknown>) => {\n const collected: Record<string, unknown> = {\n name,\n dryRun: cliOpts.dryRun,\n force: cliOpts.force,\n };\n\n // Iteratively resolve all options (prompt for missing ones)\n await resolveOptions(plugin, collected, cliOpts);\n\n closeRL();\n await plugin.execute(\n collected as ScaffoldTemplatePluginOptions & Record<string, unknown>\n );\n });\n }\n\n return newCmd;\n}\n","import path from 'path';\nimport { fileURLToPath } from 'url';\n\nimport { PluginManager } from '@libria/plugin-loader';\nimport { InteractiveCommand, Option } from 'interactive-commander';\n\nimport { registerConfigCommand, registerNewCommand } from './commands';\nimport { getPluginPaths, listPackages } from './config';\nimport { resolvePackageDir } from './utils';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\nconst PLUGINS_FOLDER = path.resolve(__dirname, '../templates').replace(/\\\\/g, '/');\n\n// Load user plugins from config\nconst userPluginPaths = await getPluginPaths();\n\n// Load plugins from npm packages\nconst packageNames = await listPackages();\n\nconst packagePaths = await Promise.all(\n packageNames.map(async name => {\n const dir = await resolvePackageDir(name);\n return dir;\n })\n);\n\nconst pluginManager = new PluginManager();\nawait pluginManager.loadPlugins([PLUGINS_FOLDER, ...userPluginPaths, ...packagePaths]);\n\nconst program = new InteractiveCommand();\nprogram.name('lb-scaffold').description('Scaffold new projects from templates');\n\nawait registerNewCommand(program, pluginManager);\nawait registerConfigCommand(program);\n\n// Enable interactive mode by default\nprogram.addOption(new Option('-i, --interactive', 'Run in interactive mode').default(true));\n\nawait program.interactive().parseAsync();\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
- //#region rolldown:runtime
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -29,15 +30,9 @@ let fs_promises = require("fs/promises");
29
30
  fs_promises = __toESM(fs_promises);
30
31
  let path = require("path");
31
32
  path = __toESM(path);
32
- let fs_extra = require("fs-extra");
33
- fs_extra = __toESM(fs_extra);
34
33
  let node_child_process = require("node:child_process");
35
34
  let node_util = require("node:util");
36
35
 
37
- //#region src/core/types.ts
38
- const SCAFFOLD_TEMPLATE_PLUGIN_TYPE = "scaffold-template";
39
-
40
- //#endregion
41
36
  //#region src/config.ts
42
37
  const CONFIG_FILENAME = ".lbscaffold";
43
38
  /**
@@ -169,24 +164,6 @@ async function listPackages(configPath) {
169
164
  return (await loadConfig(configPath)).packages ?? [];
170
165
  }
171
166
 
172
- //#endregion
173
- //#region src/utils/replace-placeholders.ts
174
- async function replacePlaceholders(targetDir, replacements) {
175
- async function replaceInFiles(folder) {
176
- const entries = await fs_extra.default.readdir(folder);
177
- for (const entry of entries) {
178
- const fullPath = path.default.join(folder, entry);
179
- if ((await fs_extra.default.stat(fullPath)).isDirectory()) await replaceInFiles(fullPath);
180
- else if (/\.(ts|js|json|md|txt)$/i.test(entry)) {
181
- let content = await fs_extra.default.readFile(fullPath, "utf-8");
182
- for (const [placeholder, value] of Object.entries(replacements)) content = content.replaceAll(placeholder, value);
183
- await fs_extra.default.writeFile(fullPath, content, "utf-8");
184
- }
185
- }
186
- }
187
- await replaceInFiles(targetDir);
188
- }
189
-
190
167
  //#endregion
191
168
  //#region src/utils/resolve-package.ts
192
169
  const execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
@@ -225,7 +202,6 @@ async function getGlobalNodeModulesDir() {
225
202
  }
226
203
 
227
204
  //#endregion
228
- exports.SCAFFOLD_TEMPLATE_PLUGIN_TYPE = SCAFFOLD_TEMPLATE_PLUGIN_TYPE;
229
205
  exports.addPackage = addPackage;
230
206
  exports.addPluginGlob = addPluginGlob;
231
207
  exports.findConfigPath = findConfigPath;
@@ -237,7 +213,6 @@ exports.listPluginGlobs = listPluginGlobs;
237
213
  exports.loadConfig = loadConfig;
238
214
  exports.removePackage = removePackage;
239
215
  exports.removePluginGlob = removePluginGlob;
240
- exports.replacePlaceholders = replacePlaceholders;
241
216
  exports.resolvePackageDir = resolvePackageDir;
242
217
  exports.saveConfig = saveConfig;
243
218
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["fs","fs","execFile","fs"],"sources":["../../src/core/types.ts","../../src/config.ts","../../src/utils/replace-placeholders.ts","../../src/utils/resolve-package.ts"],"sourcesContent":["export const SCAFFOLD_TEMPLATE_PLUGIN_TYPE = 'scaffold-template';\n\nexport type ScaffoldTemplatePluginOption<TValue = string | boolean | number> = {\n readonly flags: string; // ex: --git-init\n readonly required?: boolean;\n readonly description: string;\n readonly defaultValue?: TValue | TValue[];\n readonly choices?: TValue[];\n};\n\nexport type ResolvedOptions<TOpt extends object> = {\n [k in keyof TOpt]: TOpt[k] extends ScaffoldTemplatePluginOption<infer TValue> ? TValue : never;\n};\n\nexport type ExecuteOptions<TOpt extends object> = ScaffoldTemplatePluginOptions & {\n [k in keyof TOpt]: TOpt[k] extends ScaffoldTemplatePluginOption<infer TValue> ? TValue : never;\n};\n\nexport interface ScaffoldTemplatePlugin<TOpt extends object = object> {\n readonly argument: string;\n\n getOptions(options: ScaffoldTemplatePluginOptions & Partial<ResolvedOptions<TOpt>>): Promise<\n Partial<{\n [k in keyof TOpt]: ScaffoldTemplatePluginOption;\n }>\n >;\n\n execute(options: ExecuteOptions<TOpt>): Promise<void>;\n}\n\nexport type ScaffoldTemplatePluginOptions = {\n name: string;\n dryRun?: boolean;\n force?: boolean;\n};\n","import fs from 'fs/promises';\nimport path from 'path';\n\nexport interface LbScaffoldConfig {\n plugins?: string[];\n packages?: string[];\n}\n\nconst CONFIG_FILENAME = '.lbscaffold';\n\n/**\n * Find the config file by searching up the directory tree\n */\nexport async function findConfigPath(startDir: string = process.cwd()): Promise<string | null> {\n let currentDir = startDir;\n\n while (true) {\n const configPath = path.join(currentDir, CONFIG_FILENAME);\n try {\n await fs.access(configPath);\n return configPath;\n } catch {\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n // Reached root\n return null;\n }\n currentDir = parentDir;\n }\n }\n}\n\n/**\n * Get the default config path in the current directory\n */\nexport function getDefaultConfigPath(): string {\n return path.join(process.cwd(), CONFIG_FILENAME);\n}\n\n/**\n * Load the config file\n */\nexport async function loadConfig(configPath?: string): Promise<LbScaffoldConfig> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n return {};\n }\n\n try {\n const content = await fs.readFile(resolvedPath, 'utf-8');\n return JSON.parse(content) as LbScaffoldConfig;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw new Error(`Failed to load config from ${resolvedPath}: ${(error as Error).message}`);\n }\n}\n\n/**\n * Save the config file\n */\nexport async function saveConfig(config: LbScaffoldConfig, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n await fs.writeFile(resolvedPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Initialize a new config file\n */\nexport async function initConfig(configPath?: string): Promise<string> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n\n try {\n await fs.access(resolvedPath);\n throw new Error(`Config file already exists at ${resolvedPath}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n\n const defaultConfig: LbScaffoldConfig = {\n plugins: ['./plugins/**'],\n packages: [],\n };\n\n await saveConfig(defaultConfig, resolvedPath);\n return resolvedPath;\n}\n\n/**\n * Add a plugin glob pattern to the config\n */\nexport async function addPluginGlob(glob: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.plugins) {\n config.plugins = [];\n }\n\n if (config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' already exists in config`);\n }\n\n config.plugins.push(glob);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove a plugin glob pattern from the config\n */\nexport async function removePluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.plugins || !config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' not found in config`);\n }\n\n config.plugins = config.plugins.filter(p => p !== glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all plugin glob patterns in the config\n */\nexport async function listPluginGlobs(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.plugins ?? [];\n}\n\n/**\n * Get absolute plugin paths from config globs\n */\nexport async function getPluginPaths(configPath?: string): Promise<string[]> {\n const resolvedConfigPath = configPath ?? (await findConfigPath());\n\n if (!resolvedConfigPath) {\n return [];\n }\n\n const config = await loadConfig(resolvedConfigPath);\n const configDir = path.dirname(resolvedConfigPath);\n\n return (config.plugins ?? []).map(glob => {\n // If glob is absolute, use as-is; otherwise resolve relative to config file\n if (path.isAbsolute(glob)) {\n return glob.replace(/\\\\/g, '/');\n }\n return path.resolve(configDir, glob).replace(/\\\\/g, '/');\n });\n}\n\n/**\n * Add an npm package name to the config\n */\nexport async function addPackage(packageName: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.packages) {\n config.packages = [];\n }\n\n if (config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' already exists in config`);\n }\n\n config.packages.push(packageName);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove an npm package name from the config\n */\nexport async function removePackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.packages || !config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' not found in config`);\n }\n\n config.packages = config.packages.filter(p => p !== packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all npm package names in the config\n */\nexport async function listPackages(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.packages ?? [];\n}\n","import path from 'path';\n\nimport fs from 'fs-extra';\n\nexport async function replacePlaceholders<T extends Record<string, string>>(\n targetDir: string,\n replacements: T\n): Promise<void> {\n async function replaceInFiles(folder: string): Promise<void> {\n const entries = await fs.readdir(folder);\n for (const entry of entries) {\n const fullPath = path.join(folder, entry);\n const stat = await fs.stat(fullPath);\n if (stat.isDirectory()) {\n await replaceInFiles(fullPath);\n } else if (/\\.(ts|js|json|md|txt)$/i.test(entry)) {\n let content = await fs.readFile(fullPath, 'utf-8');\n for (const [placeholder, value] of Object.entries(replacements)) {\n content = content.replaceAll(placeholder, value);\n }\n await fs.writeFile(fullPath, content, 'utf-8');\n }\n }\n }\n\n await replaceInFiles(targetDir);\n}\n","import fs from 'fs/promises';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport path from 'path';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Resolve an npm package name to its installed root directory.\n * Tries local node_modules first (relative to cwd), then global.\n */\nexport async function resolvePackageDir(packageName: string): Promise<string> {\n // Strategy 1: resolve from local node_modules via cwd\n const localCandidate = path.join(process.cwd(), 'node_modules', packageName);\n try {\n await fs.access(path.join(localCandidate, 'package.json'));\n return localCandidate;\n } catch {\n // Not found locally, try global\n }\n\n // Strategy 2: resolve from global node_modules\n const globalDir = await getGlobalNodeModulesDir();\n if (globalDir) {\n const globalCandidate = path.join(globalDir, packageName);\n try {\n await fs.access(path.join(globalCandidate, 'package.json'));\n return globalCandidate;\n } catch {\n // Not found globally either\n }\n }\n\n throw new Error(\n `Package '${packageName}' not found. ` +\n `Install it locally (npm install ${packageName}) or globally (npm install -g ${packageName}).`\n );\n}\n\n/**\n * Get the global node_modules directory using npm root -g.\n */\nasync function getGlobalNodeModulesDir(): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync('npm', ['root', '-g'], { encoding: 'utf-8' });\n const dir = stdout.trim();\n await fs.access(dir);\n return dir;\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["fs","execFile","fs"],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts"],"sourcesContent":["import fs from 'fs/promises';\nimport path from 'path';\n\nexport interface LbScaffoldConfig {\n plugins?: string[];\n packages?: string[];\n}\n\nconst CONFIG_FILENAME = '.lbscaffold';\n\n/**\n * Find the config file by searching up the directory tree\n */\nexport async function findConfigPath(startDir: string = process.cwd()): Promise<string | null> {\n let currentDir = startDir;\n\n while (true) {\n const configPath = path.join(currentDir, CONFIG_FILENAME);\n try {\n await fs.access(configPath);\n return configPath;\n } catch {\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n // Reached root\n return null;\n }\n currentDir = parentDir;\n }\n }\n}\n\n/**\n * Get the default config path in the current directory\n */\nexport function getDefaultConfigPath(): string {\n return path.join(process.cwd(), CONFIG_FILENAME);\n}\n\n/**\n * Load the config file\n */\nexport async function loadConfig(configPath?: string): Promise<LbScaffoldConfig> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n return {};\n }\n\n try {\n const content = await fs.readFile(resolvedPath, 'utf-8');\n return JSON.parse(content) as LbScaffoldConfig;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw new Error(`Failed to load config from ${resolvedPath}: ${(error as Error).message}`);\n }\n}\n\n/**\n * Save the config file\n */\nexport async function saveConfig(config: LbScaffoldConfig, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n await fs.writeFile(resolvedPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Initialize a new config file\n */\nexport async function initConfig(configPath?: string): Promise<string> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n\n try {\n await fs.access(resolvedPath);\n throw new Error(`Config file already exists at ${resolvedPath}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n\n const defaultConfig: LbScaffoldConfig = {\n plugins: ['./plugins/**'],\n packages: [],\n };\n\n await saveConfig(defaultConfig, resolvedPath);\n return resolvedPath;\n}\n\n/**\n * Add a plugin glob pattern to the config\n */\nexport async function addPluginGlob(glob: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.plugins) {\n config.plugins = [];\n }\n\n if (config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' already exists in config`);\n }\n\n config.plugins.push(glob);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove a plugin glob pattern from the config\n */\nexport async function removePluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.plugins || !config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' not found in config`);\n }\n\n config.plugins = config.plugins.filter(p => p !== glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all plugin glob patterns in the config\n */\nexport async function listPluginGlobs(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.plugins ?? [];\n}\n\n/**\n * Get absolute plugin paths from config globs\n */\nexport async function getPluginPaths(configPath?: string): Promise<string[]> {\n const resolvedConfigPath = configPath ?? (await findConfigPath());\n\n if (!resolvedConfigPath) {\n return [];\n }\n\n const config = await loadConfig(resolvedConfigPath);\n const configDir = path.dirname(resolvedConfigPath);\n\n return (config.plugins ?? []).map(glob => {\n // If glob is absolute, use as-is; otherwise resolve relative to config file\n if (path.isAbsolute(glob)) {\n return glob.replace(/\\\\/g, '/');\n }\n return path.resolve(configDir, glob).replace(/\\\\/g, '/');\n });\n}\n\n/**\n * Add an npm package name to the config\n */\nexport async function addPackage(packageName: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.packages) {\n config.packages = [];\n }\n\n if (config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' already exists in config`);\n }\n\n config.packages.push(packageName);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove an npm package name from the config\n */\nexport async function removePackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.packages || !config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' not found in config`);\n }\n\n config.packages = config.packages.filter(p => p !== packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all npm package names in the config\n */\nexport async function listPackages(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.packages ?? [];\n}\n","import fs from 'fs/promises';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport path from 'path';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Resolve an npm package name to its installed root directory.\n * Tries local node_modules first (relative to cwd), then global.\n */\nexport async function resolvePackageDir(packageName: string): Promise<string> {\n // Strategy 1: resolve from local node_modules via cwd\n const localCandidate = path.join(process.cwd(), 'node_modules', packageName);\n try {\n await fs.access(path.join(localCandidate, 'package.json'));\n return localCandidate;\n } catch {\n // Not found locally, try global\n }\n\n // Strategy 2: resolve from global node_modules\n const globalDir = await getGlobalNodeModulesDir();\n if (globalDir) {\n const globalCandidate = path.join(globalDir, packageName);\n try {\n await fs.access(path.join(globalCandidate, 'package.json'));\n return globalCandidate;\n } catch {\n // Not found globally either\n }\n }\n\n throw new Error(\n `Package '${packageName}' not found. ` +\n `Install it locally (npm install ${packageName}) or globally (npm install -g ${packageName}).`\n );\n}\n\n/**\n * Get the global node_modules directory using npm root -g.\n */\nasync function getGlobalNodeModulesDir(): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync('npm', ['root', '-g'], { encoding: 'utf-8' });\n const dir = stdout.trim();\n await fs.access(dir);\n return dir;\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
@@ -1,25 +1,3 @@
1
- //#region src/core/types.d.ts
2
- declare const SCAFFOLD_TEMPLATE_PLUGIN_TYPE = "scaffold-template";
3
- type ScaffoldTemplatePluginOption<TValue = string | boolean | number> = {
4
- readonly flags: string;
5
- readonly required?: boolean;
6
- readonly description: string;
7
- readonly defaultValue?: TValue | TValue[];
8
- readonly choices?: TValue[];
9
- };
10
- type ResolvedOptions<TOpt extends object> = { [k in keyof TOpt]: TOpt[k] extends ScaffoldTemplatePluginOption<infer TValue> ? TValue : never };
11
- type ExecuteOptions<TOpt extends object> = ScaffoldTemplatePluginOptions & { [k in keyof TOpt]: TOpt[k] extends ScaffoldTemplatePluginOption<infer TValue> ? TValue : never };
12
- interface ScaffoldTemplatePlugin<TOpt extends object = object> {
13
- readonly argument: string;
14
- getOptions(options: ScaffoldTemplatePluginOptions & Partial<ResolvedOptions<TOpt>>): Promise<Partial<{ [k in keyof TOpt]: ScaffoldTemplatePluginOption }>>;
15
- execute(options: ExecuteOptions<TOpt>): Promise<void>;
16
- }
17
- type ScaffoldTemplatePluginOptions = {
18
- name: string;
19
- dryRun?: boolean;
20
- force?: boolean;
21
- };
22
- //#endregion
23
1
  //#region src/config.d.ts
24
2
  interface LbScaffoldConfig {
25
3
  plugins?: string[];
@@ -74,9 +52,6 @@ declare function removePackage(packageName: string, configPath?: string): Promis
74
52
  */
75
53
  declare function listPackages(configPath?: string): Promise<string[]>;
76
54
  //#endregion
77
- //#region src/utils/replace-placeholders.d.ts
78
- declare function replacePlaceholders<T extends Record<string, string>>(targetDir: string, replacements: T): Promise<void>;
79
- //#endregion
80
55
  //#region src/utils/resolve-package.d.ts
81
56
  /**
82
57
  * Resolve an npm package name to its installed root directory.
@@ -84,5 +59,5 @@ declare function replacePlaceholders<T extends Record<string, string>>(targetDir
84
59
  */
85
60
  declare function resolvePackageDir(packageName: string): Promise<string>;
86
61
  //#endregion
87
- export { ExecuteOptions, LbScaffoldConfig, ResolvedOptions, SCAFFOLD_TEMPLATE_PLUGIN_TYPE, ScaffoldTemplatePlugin, ScaffoldTemplatePluginOption, ScaffoldTemplatePluginOptions, addPackage, addPluginGlob, findConfigPath, getDefaultConfigPath, getPluginPaths, initConfig, listPackages, listPluginGlobs, loadConfig, removePackage, removePluginGlob, replacePlaceholders, resolvePackageDir, saveConfig };
62
+ export { LbScaffoldConfig, addPackage, addPluginGlob, findConfigPath, getDefaultConfigPath, getPluginPaths, initConfig, listPackages, listPluginGlobs, loadConfig, removePackage, removePluginGlob, resolvePackageDir, saveConfig };
88
63
  //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts"],"mappings":";UAGiB,gBAAA;EACb,OAAA;EACA,QAAA;AAAA;;;AAQJ;iBAAsB,cAAA,CAAe,QAAA,YAAmC,OAAA;;;;iBAsBxD,oBAAA,CAAA;;;;iBAOM,UAAA,CAAW,UAAA,YAAsB,OAAA,CAAQ,gBAAA;AAA/D;;;AAAA,iBAqBsB,UAAA,CAAW,MAAA,EAAQ,gBAAA,EAAkB,UAAA,YAAsB,OAAA;;;;iBAQ3D,UAAA,CAAW,UAAA,YAAsB,OAAA;;AARvD;;iBAgCsB,aAAA,CAAc,IAAA,UAAc,UAAA,YAAsB,OAAA;;;;iBAkBlD,gBAAA,CAAiB,IAAA,UAAc,UAAA,YAAsB,OAAA;;;;iBAoBrD,eAAA,CAAgB,UAAA,YAAsB,OAAA;;;;iBAQtC,cAAA,CAAe,UAAA,YAAsB,OAAA;AA9C3D;;;AAAA,iBAoEsB,UAAA,CAAW,WAAA,UAAqB,UAAA,YAAsB,OAAA;;;;iBAkBtD,aAAA,CAAc,WAAA,UAAqB,UAAA,YAAsB,OAAA;;AApE/E;;iBAwFsB,YAAA,CAAa,UAAA,YAAsB,OAAA;;;;AAtMzD;;;iBCQsB,iBAAA,CAAkB,WAAA,WAAsB,OAAA"}
@@ -1,25 +1,3 @@
1
- //#region src/core/types.d.ts
2
- declare const SCAFFOLD_TEMPLATE_PLUGIN_TYPE = "scaffold-template";
3
- type ScaffoldTemplatePluginOption<TValue = string | boolean | number> = {
4
- readonly flags: string;
5
- readonly required?: boolean;
6
- readonly description: string;
7
- readonly defaultValue?: TValue | TValue[];
8
- readonly choices?: TValue[];
9
- };
10
- type ResolvedOptions<TOpt extends object> = { [k in keyof TOpt]: TOpt[k] extends ScaffoldTemplatePluginOption<infer TValue> ? TValue : never };
11
- type ExecuteOptions<TOpt extends object> = ScaffoldTemplatePluginOptions & { [k in keyof TOpt]: TOpt[k] extends ScaffoldTemplatePluginOption<infer TValue> ? TValue : never };
12
- interface ScaffoldTemplatePlugin<TOpt extends object = object> {
13
- readonly argument: string;
14
- getOptions(options: ScaffoldTemplatePluginOptions & Partial<ResolvedOptions<TOpt>>): Promise<Partial<{ [k in keyof TOpt]: ScaffoldTemplatePluginOption }>>;
15
- execute(options: ExecuteOptions<TOpt>): Promise<void>;
16
- }
17
- type ScaffoldTemplatePluginOptions = {
18
- name: string;
19
- dryRun?: boolean;
20
- force?: boolean;
21
- };
22
- //#endregion
23
1
  //#region src/config.d.ts
24
2
  interface LbScaffoldConfig {
25
3
  plugins?: string[];
@@ -74,9 +52,6 @@ declare function removePackage(packageName: string, configPath?: string): Promis
74
52
  */
75
53
  declare function listPackages(configPath?: string): Promise<string[]>;
76
54
  //#endregion
77
- //#region src/utils/replace-placeholders.d.ts
78
- declare function replacePlaceholders<T extends Record<string, string>>(targetDir: string, replacements: T): Promise<void>;
79
- //#endregion
80
55
  //#region src/utils/resolve-package.d.ts
81
56
  /**
82
57
  * Resolve an npm package name to its installed root directory.
@@ -84,5 +59,5 @@ declare function replacePlaceholders<T extends Record<string, string>>(targetDir
84
59
  */
85
60
  declare function resolvePackageDir(packageName: string): Promise<string>;
86
61
  //#endregion
87
- export { ExecuteOptions, LbScaffoldConfig, ResolvedOptions, SCAFFOLD_TEMPLATE_PLUGIN_TYPE, ScaffoldTemplatePlugin, ScaffoldTemplatePluginOption, ScaffoldTemplatePluginOptions, addPackage, addPluginGlob, findConfigPath, getDefaultConfigPath, getPluginPaths, initConfig, listPackages, listPluginGlobs, loadConfig, removePackage, removePluginGlob, replacePlaceholders, resolvePackageDir, saveConfig };
62
+ export { LbScaffoldConfig, addPackage, addPluginGlob, findConfigPath, getDefaultConfigPath, getPluginPaths, initConfig, listPackages, listPluginGlobs, loadConfig, removePackage, removePluginGlob, resolvePackageDir, saveConfig };
88
63
  //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts"],"mappings":";UAGiB,gBAAA;EACb,OAAA;EACA,QAAA;AAAA;;;AAQJ;iBAAsB,cAAA,CAAe,QAAA,YAAmC,OAAA;;;;iBAsBxD,oBAAA,CAAA;;;;iBAOM,UAAA,CAAW,UAAA,YAAsB,OAAA,CAAQ,gBAAA;AAA/D;;;AAAA,iBAqBsB,UAAA,CAAW,MAAA,EAAQ,gBAAA,EAAkB,UAAA,YAAsB,OAAA;;;;iBAQ3D,UAAA,CAAW,UAAA,YAAsB,OAAA;;AARvD;;iBAgCsB,aAAA,CAAc,IAAA,UAAc,UAAA,YAAsB,OAAA;;;;iBAkBlD,gBAAA,CAAiB,IAAA,UAAc,UAAA,YAAsB,OAAA;;;;iBAoBrD,eAAA,CAAgB,UAAA,YAAsB,OAAA;;;;iBAQtC,cAAA,CAAe,UAAA,YAAsB,OAAA;AA9C3D;;;AAAA,iBAoEsB,UAAA,CAAW,WAAA,UAAqB,UAAA,YAAsB,OAAA;;;;iBAkBtD,aAAA,CAAc,WAAA,UAAqB,UAAA,YAAsB,OAAA;;AApE/E;;iBAwFsB,YAAA,CAAa,UAAA,YAAsB,OAAA;;;;AAtMzD;;;iBCQsB,iBAAA,CAAkB,WAAA,WAAsB,OAAA"}
@@ -1,13 +1,8 @@
1
1
  import fs from "fs/promises";
2
2
  import path from "path";
3
- import fs$1 from "fs-extra";
4
3
  import { execFile } from "node:child_process";
5
4
  import { promisify } from "node:util";
6
5
 
7
- //#region src/core/types.ts
8
- const SCAFFOLD_TEMPLATE_PLUGIN_TYPE = "scaffold-template";
9
-
10
- //#endregion
11
6
  //#region src/config.ts
12
7
  const CONFIG_FILENAME = ".lbscaffold";
13
8
  /**
@@ -139,24 +134,6 @@ async function listPackages(configPath) {
139
134
  return (await loadConfig(configPath)).packages ?? [];
140
135
  }
141
136
 
142
- //#endregion
143
- //#region src/utils/replace-placeholders.ts
144
- async function replacePlaceholders(targetDir, replacements) {
145
- async function replaceInFiles(folder) {
146
- const entries = await fs$1.readdir(folder);
147
- for (const entry of entries) {
148
- const fullPath = path.join(folder, entry);
149
- if ((await fs$1.stat(fullPath)).isDirectory()) await replaceInFiles(fullPath);
150
- else if (/\.(ts|js|json|md|txt)$/i.test(entry)) {
151
- let content = await fs$1.readFile(fullPath, "utf-8");
152
- for (const [placeholder, value] of Object.entries(replacements)) content = content.replaceAll(placeholder, value);
153
- await fs$1.writeFile(fullPath, content, "utf-8");
154
- }
155
- }
156
- }
157
- await replaceInFiles(targetDir);
158
- }
159
-
160
137
  //#endregion
161
138
  //#region src/utils/resolve-package.ts
162
139
  const execFileAsync = promisify(execFile);
@@ -195,5 +172,5 @@ async function getGlobalNodeModulesDir() {
195
172
  }
196
173
 
197
174
  //#endregion
198
- export { SCAFFOLD_TEMPLATE_PLUGIN_TYPE, addPackage, addPluginGlob, findConfigPath, getDefaultConfigPath, getPluginPaths, initConfig, listPackages, listPluginGlobs, loadConfig, removePackage, removePluginGlob, replacePlaceholders, resolvePackageDir, saveConfig };
175
+ export { addPackage, addPluginGlob, findConfigPath, getDefaultConfigPath, getPluginPaths, initConfig, listPackages, listPluginGlobs, loadConfig, removePackage, removePluginGlob, resolvePackageDir, saveConfig };
199
176
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["fs"],"sources":["../../src/core/types.ts","../../src/config.ts","../../src/utils/replace-placeholders.ts","../../src/utils/resolve-package.ts"],"sourcesContent":["export const SCAFFOLD_TEMPLATE_PLUGIN_TYPE = 'scaffold-template';\n\nexport type ScaffoldTemplatePluginOption<TValue = string | boolean | number> = {\n readonly flags: string; // ex: --git-init\n readonly required?: boolean;\n readonly description: string;\n readonly defaultValue?: TValue | TValue[];\n readonly choices?: TValue[];\n};\n\nexport type ResolvedOptions<TOpt extends object> = {\n [k in keyof TOpt]: TOpt[k] extends ScaffoldTemplatePluginOption<infer TValue> ? TValue : never;\n};\n\nexport type ExecuteOptions<TOpt extends object> = ScaffoldTemplatePluginOptions & {\n [k in keyof TOpt]: TOpt[k] extends ScaffoldTemplatePluginOption<infer TValue> ? TValue : never;\n};\n\nexport interface ScaffoldTemplatePlugin<TOpt extends object = object> {\n readonly argument: string;\n\n getOptions(options: ScaffoldTemplatePluginOptions & Partial<ResolvedOptions<TOpt>>): Promise<\n Partial<{\n [k in keyof TOpt]: ScaffoldTemplatePluginOption;\n }>\n >;\n\n execute(options: ExecuteOptions<TOpt>): Promise<void>;\n}\n\nexport type ScaffoldTemplatePluginOptions = {\n name: string;\n dryRun?: boolean;\n force?: boolean;\n};\n","import fs from 'fs/promises';\nimport path from 'path';\n\nexport interface LbScaffoldConfig {\n plugins?: string[];\n packages?: string[];\n}\n\nconst CONFIG_FILENAME = '.lbscaffold';\n\n/**\n * Find the config file by searching up the directory tree\n */\nexport async function findConfigPath(startDir: string = process.cwd()): Promise<string | null> {\n let currentDir = startDir;\n\n while (true) {\n const configPath = path.join(currentDir, CONFIG_FILENAME);\n try {\n await fs.access(configPath);\n return configPath;\n } catch {\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n // Reached root\n return null;\n }\n currentDir = parentDir;\n }\n }\n}\n\n/**\n * Get the default config path in the current directory\n */\nexport function getDefaultConfigPath(): string {\n return path.join(process.cwd(), CONFIG_FILENAME);\n}\n\n/**\n * Load the config file\n */\nexport async function loadConfig(configPath?: string): Promise<LbScaffoldConfig> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n return {};\n }\n\n try {\n const content = await fs.readFile(resolvedPath, 'utf-8');\n return JSON.parse(content) as LbScaffoldConfig;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw new Error(`Failed to load config from ${resolvedPath}: ${(error as Error).message}`);\n }\n}\n\n/**\n * Save the config file\n */\nexport async function saveConfig(config: LbScaffoldConfig, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n await fs.writeFile(resolvedPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Initialize a new config file\n */\nexport async function initConfig(configPath?: string): Promise<string> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n\n try {\n await fs.access(resolvedPath);\n throw new Error(`Config file already exists at ${resolvedPath}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n\n const defaultConfig: LbScaffoldConfig = {\n plugins: ['./plugins/**'],\n packages: [],\n };\n\n await saveConfig(defaultConfig, resolvedPath);\n return resolvedPath;\n}\n\n/**\n * Add a plugin glob pattern to the config\n */\nexport async function addPluginGlob(glob: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.plugins) {\n config.plugins = [];\n }\n\n if (config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' already exists in config`);\n }\n\n config.plugins.push(glob);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove a plugin glob pattern from the config\n */\nexport async function removePluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.plugins || !config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' not found in config`);\n }\n\n config.plugins = config.plugins.filter(p => p !== glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all plugin glob patterns in the config\n */\nexport async function listPluginGlobs(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.plugins ?? [];\n}\n\n/**\n * Get absolute plugin paths from config globs\n */\nexport async function getPluginPaths(configPath?: string): Promise<string[]> {\n const resolvedConfigPath = configPath ?? (await findConfigPath());\n\n if (!resolvedConfigPath) {\n return [];\n }\n\n const config = await loadConfig(resolvedConfigPath);\n const configDir = path.dirname(resolvedConfigPath);\n\n return (config.plugins ?? []).map(glob => {\n // If glob is absolute, use as-is; otherwise resolve relative to config file\n if (path.isAbsolute(glob)) {\n return glob.replace(/\\\\/g, '/');\n }\n return path.resolve(configDir, glob).replace(/\\\\/g, '/');\n });\n}\n\n/**\n * Add an npm package name to the config\n */\nexport async function addPackage(packageName: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.packages) {\n config.packages = [];\n }\n\n if (config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' already exists in config`);\n }\n\n config.packages.push(packageName);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove an npm package name from the config\n */\nexport async function removePackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.packages || !config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' not found in config`);\n }\n\n config.packages = config.packages.filter(p => p !== packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all npm package names in the config\n */\nexport async function listPackages(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.packages ?? [];\n}\n","import path from 'path';\n\nimport fs from 'fs-extra';\n\nexport async function replacePlaceholders<T extends Record<string, string>>(\n targetDir: string,\n replacements: T\n): Promise<void> {\n async function replaceInFiles(folder: string): Promise<void> {\n const entries = await fs.readdir(folder);\n for (const entry of entries) {\n const fullPath = path.join(folder, entry);\n const stat = await fs.stat(fullPath);\n if (stat.isDirectory()) {\n await replaceInFiles(fullPath);\n } else if (/\\.(ts|js|json|md|txt)$/i.test(entry)) {\n let content = await fs.readFile(fullPath, 'utf-8');\n for (const [placeholder, value] of Object.entries(replacements)) {\n content = content.replaceAll(placeholder, value);\n }\n await fs.writeFile(fullPath, content, 'utf-8');\n }\n }\n }\n\n await replaceInFiles(targetDir);\n}\n","import fs from 'fs/promises';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport path from 'path';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Resolve an npm package name to its installed root directory.\n * Tries local node_modules first (relative to cwd), then global.\n */\nexport async function resolvePackageDir(packageName: string): Promise<string> {\n // Strategy 1: resolve from local node_modules via cwd\n const localCandidate = path.join(process.cwd(), 'node_modules', packageName);\n try {\n await fs.access(path.join(localCandidate, 'package.json'));\n return localCandidate;\n } catch {\n // Not found locally, try global\n }\n\n // Strategy 2: resolve from global node_modules\n const globalDir = await getGlobalNodeModulesDir();\n if (globalDir) {\n const globalCandidate = path.join(globalDir, packageName);\n try {\n await fs.access(path.join(globalCandidate, 'package.json'));\n return globalCandidate;\n } catch {\n // Not found globally either\n }\n }\n\n throw new Error(\n `Package '${packageName}' not found. ` +\n `Install it locally (npm install ${packageName}) or globally (npm install -g ${packageName}).`\n );\n}\n\n/**\n * Get the global node_modules directory using npm root -g.\n */\nasync function getGlobalNodeModulesDir(): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync('npm', ['root', '-g'], { encoding: 'utf-8' });\n const dir = stdout.trim();\n await fs.access(dir);\n return dir;\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts"],"sourcesContent":["import fs from 'fs/promises';\nimport path from 'path';\n\nexport interface LbScaffoldConfig {\n plugins?: string[];\n packages?: string[];\n}\n\nconst CONFIG_FILENAME = '.lbscaffold';\n\n/**\n * Find the config file by searching up the directory tree\n */\nexport async function findConfigPath(startDir: string = process.cwd()): Promise<string | null> {\n let currentDir = startDir;\n\n while (true) {\n const configPath = path.join(currentDir, CONFIG_FILENAME);\n try {\n await fs.access(configPath);\n return configPath;\n } catch {\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n // Reached root\n return null;\n }\n currentDir = parentDir;\n }\n }\n}\n\n/**\n * Get the default config path in the current directory\n */\nexport function getDefaultConfigPath(): string {\n return path.join(process.cwd(), CONFIG_FILENAME);\n}\n\n/**\n * Load the config file\n */\nexport async function loadConfig(configPath?: string): Promise<LbScaffoldConfig> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n return {};\n }\n\n try {\n const content = await fs.readFile(resolvedPath, 'utf-8');\n return JSON.parse(content) as LbScaffoldConfig;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw new Error(`Failed to load config from ${resolvedPath}: ${(error as Error).message}`);\n }\n}\n\n/**\n * Save the config file\n */\nexport async function saveConfig(config: LbScaffoldConfig, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n await fs.writeFile(resolvedPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Initialize a new config file\n */\nexport async function initConfig(configPath?: string): Promise<string> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n\n try {\n await fs.access(resolvedPath);\n throw new Error(`Config file already exists at ${resolvedPath}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n\n const defaultConfig: LbScaffoldConfig = {\n plugins: ['./plugins/**'],\n packages: [],\n };\n\n await saveConfig(defaultConfig, resolvedPath);\n return resolvedPath;\n}\n\n/**\n * Add a plugin glob pattern to the config\n */\nexport async function addPluginGlob(glob: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.plugins) {\n config.plugins = [];\n }\n\n if (config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' already exists in config`);\n }\n\n config.plugins.push(glob);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove a plugin glob pattern from the config\n */\nexport async function removePluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.plugins || !config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' not found in config`);\n }\n\n config.plugins = config.plugins.filter(p => p !== glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all plugin glob patterns in the config\n */\nexport async function listPluginGlobs(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.plugins ?? [];\n}\n\n/**\n * Get absolute plugin paths from config globs\n */\nexport async function getPluginPaths(configPath?: string): Promise<string[]> {\n const resolvedConfigPath = configPath ?? (await findConfigPath());\n\n if (!resolvedConfigPath) {\n return [];\n }\n\n const config = await loadConfig(resolvedConfigPath);\n const configDir = path.dirname(resolvedConfigPath);\n\n return (config.plugins ?? []).map(glob => {\n // If glob is absolute, use as-is; otherwise resolve relative to config file\n if (path.isAbsolute(glob)) {\n return glob.replace(/\\\\/g, '/');\n }\n return path.resolve(configDir, glob).replace(/\\\\/g, '/');\n });\n}\n\n/**\n * Add an npm package name to the config\n */\nexport async function addPackage(packageName: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.packages) {\n config.packages = [];\n }\n\n if (config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' already exists in config`);\n }\n\n config.packages.push(packageName);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove an npm package name from the config\n */\nexport async function removePackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.packages || !config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' not found in config`);\n }\n\n config.packages = config.packages.filter(p => p !== packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all npm package names in the config\n */\nexport async function listPackages(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.packages ?? [];\n}\n","import fs from 'fs/promises';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport path from 'path';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Resolve an npm package name to its installed root directory.\n * Tries local node_modules first (relative to cwd), then global.\n */\nexport async function resolvePackageDir(packageName: string): Promise<string> {\n // Strategy 1: resolve from local node_modules via cwd\n const localCandidate = path.join(process.cwd(), 'node_modules', packageName);\n try {\n await fs.access(path.join(localCandidate, 'package.json'));\n return localCandidate;\n } catch {\n // Not found locally, try global\n }\n\n // Strategy 2: resolve from global node_modules\n const globalDir = await getGlobalNodeModulesDir();\n if (globalDir) {\n const globalCandidate = path.join(globalDir, packageName);\n try {\n await fs.access(path.join(globalCandidate, 'package.json'));\n return globalCandidate;\n } catch {\n // Not found globally either\n }\n }\n\n throw new Error(\n `Package '${packageName}' not found. ` +\n `Install it locally (npm install ${packageName}) or globally (npm install -g ${packageName}).`\n );\n}\n\n/**\n * Get the global node_modules directory using npm root -g.\n */\nasync function getGlobalNodeModulesDir(): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync('npm', ['root', '-g'], { encoding: 'utf-8' });\n const dir = stdout.trim();\n await fs.access(dir);\n return dir;\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@libria/scaffold",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "A pluggable CLI that transforms blank directories into production-ready codebases in seconds",
5
5
  "main": "dist/cli/index.cjs",
6
6
  "module": "dist/cli/index.mjs",
@@ -36,14 +36,15 @@
36
36
  "homepage": "https://github.com/LibriaForge/scaffold#readme",
37
37
  "dependencies": {
38
38
  "@libria/plugin-loader": "^2.0.0-alpha",
39
+ "@libria/scaffold-core": "^0.3.0",
39
40
  "commander": "^14.0.3",
40
41
  "fast-glob": "^3.3.3",
41
42
  "fs-extra": "^11.3.3",
42
43
  "interactive-commander": "^0.6.0"
43
44
  },
44
45
  "optionalDependencies": {
45
- "@libria/scaffold-angular": "0.0.3",
46
- "@libria/scaffold-nestjs": "0.0.2",
47
- "@libria/scaffold-ts-lib": "0.0.3"
46
+ "@libria/scaffold-angular": "^0.0.4",
47
+ "@libria/scaffold-nestjs": "^0.0.3",
48
+ "@libria/scaffold-ts-lib": "^0.0.6"
48
49
  }
49
50
  }