@timeax/scaffold 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +2 -0
- package/dist/cli.cjs +1081 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.mjs +1070 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/index.cjs +785 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +439 -0
- package/dist/index.d.ts +439 -0
- package/dist/index.mjs +773 -0
- package/dist/index.mjs.map +1 -0
- package/docs/structure.txt +25 -0
- package/package.json +49 -0
- package/readme.md +424 -0
- package/src/cli/main.ts +244 -0
- package/src/core/apply-structure.ts +255 -0
- package/src/core/cache-manager.ts +99 -0
- package/src/core/config-loader.ts +184 -0
- package/src/core/hook-runner.ts +73 -0
- package/src/core/init-scaffold.ts +162 -0
- package/src/core/resolve-structure.ts +64 -0
- package/src/core/runner.ts +94 -0
- package/src/core/scan-structure.ts +214 -0
- package/src/core/structure-txt.ts +203 -0
- package/src/core/watcher.ts +106 -0
- package/src/index.ts +5 -0
- package/src/schema/config.ts +180 -0
- package/src/schema/hooks.ts +139 -0
- package/src/schema/index.ts +4 -0
- package/src/schema/structure.ts +77 -0
- package/src/util/fs-utils.ts +126 -0
- package/src/util/logger.ts +144 -0
- package/tsconfig.json +24 -0
- package/tsup.config.ts +48 -0
package/dist/cli.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/util/logger.ts","../src/util/fs-utils.ts","../src/core/config-loader.ts","../src/core/structure-txt.ts","../src/core/resolve-structure.ts","../src/core/cache-manager.ts","../src/core/hook-runner.ts","../src/core/apply-structure.ts","../src/core/runner.ts","../src/core/watcher.ts","../src/core/scan-structure.ts","../src/core/init-scaffold.ts","../src/cli/main.ts"],"names":["fs","path","parent","logger","minimatch"],"mappings":"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","file":"cli.mjs","sourcesContent":["// src/util/logger.ts\r\n\r\nexport type LogLevel = 'silent' | 'error' | 'warn' | 'info' | 'debug';\r\n\r\nexport interface LoggerOptions {\r\n level?: LogLevel;\r\n /**\r\n * Optional prefix string (e.g. \"[scaffold]\" or \"[group:app]\").\r\n */\r\n prefix?: string;\r\n}\r\n\r\n/**\r\n * Minimal ANSI color helpers (no external deps).\r\n */\r\nconst supportsColor =\r\n typeof process !== 'undefined' &&\r\n process.stdout &&\r\n process.stdout.isTTY &&\r\n process.env.NO_COLOR !== '1';\r\n\r\ntype ColorFn = (text: string) => string;\r\n\r\nfunction wrap(code: number): ColorFn {\r\n const open = `\\u001b[${code}m`;\r\n const close = `\\u001b[0m`;\r\n return (text: string) => (supportsColor ? `${open}${text}${close}` : text);\r\n}\r\n\r\nconst color = {\r\n red: wrap(31),\r\n yellow: wrap(33),\r\n green: wrap(32),\r\n cyan: wrap(36),\r\n magenta: wrap(35),\r\n dim: wrap(2),\r\n bold: wrap(1),\r\n gray: wrap(90),\r\n};\r\n\r\nfunction colorForLevel(level: LogLevel): ColorFn {\r\n switch (level) {\r\n case 'error':\r\n return color.red;\r\n case 'warn':\r\n return color.yellow;\r\n case 'info':\r\n return color.cyan;\r\n case 'debug':\r\n return color.gray;\r\n default:\r\n return (s) => s;\r\n }\r\n}\r\n\r\n/**\r\n * Minimal logger for @timeax/scaffold with colored output.\r\n */\r\nexport class Logger {\r\n private level: LogLevel;\r\n private prefix: string | undefined;\r\n\r\n constructor(options: LoggerOptions = {}) {\r\n this.level = options.level ?? 'info';\r\n this.prefix = options.prefix;\r\n }\r\n\r\n setLevel(level: LogLevel) {\r\n this.level = level;\r\n }\r\n\r\n getLevel(): LogLevel {\r\n return this.level;\r\n }\r\n\r\n /**\r\n * Create a child logger with an additional prefix.\r\n */\r\n child(prefix: string): Logger {\r\n const combined = this.prefix ? `${this.prefix}${prefix}` : prefix;\r\n return new Logger({ level: this.level, prefix: combined });\r\n }\r\n\r\n private formatMessage(msg: unknown, lvl: LogLevel): string {\r\n const text =\r\n typeof msg === 'string'\r\n ? msg\r\n : msg instanceof Error\r\n ? msg.message\r\n : String(msg);\r\n\r\n const levelColor = colorForLevel(lvl);\r\n const prefixColored = this.prefix\r\n ? color.magenta(this.prefix)\r\n : undefined;\r\n\r\n const textColored =\r\n lvl === 'debug' ? color.dim(text) : levelColor(text);\r\n\r\n if (prefixColored) {\r\n return `${prefixColored} ${textColored}`;\r\n }\r\n\r\n return textColored;\r\n }\r\n\r\n private shouldLog(targetLevel: LogLevel): boolean {\r\n const order: LogLevel[] = ['silent', 'error', 'warn', 'info', 'debug'];\r\n const currentIdx = order.indexOf(this.level);\r\n const targetIdx = order.indexOf(targetLevel);\r\n if (currentIdx === -1 || targetIdx === -1) return true;\r\n if (this.level === 'silent') return false;\r\n return targetIdx <= currentIdx || targetLevel === 'error';\r\n }\r\n\r\n error(msg: unknown, ...rest: unknown[]) {\r\n if (!this.shouldLog('error')) return;\r\n console.error(this.formatMessage(msg, 'error'), ...rest);\r\n }\r\n\r\n warn(msg: unknown, ...rest: unknown[]) {\r\n if (!this.shouldLog('warn')) return;\r\n console.warn(this.formatMessage(msg, 'warn'), ...rest);\r\n }\r\n\r\n info(msg: unknown, ...rest: unknown[]) {\r\n if (!this.shouldLog('info')) return;\r\n console.log(this.formatMessage(msg, 'info'), ...rest);\r\n }\r\n\r\n debug(msg: unknown, ...rest: unknown[]) {\r\n if (!this.shouldLog('debug')) return;\r\n console.debug(this.formatMessage(msg, 'debug'), ...rest);\r\n }\r\n}\r\n\r\n/**\r\n * Default process-wide logger used by CLI and core.\r\n * Level can be controlled via SCAFFOLD_LOG_LEVEL env.\r\n */\r\nexport const defaultLogger = new Logger({\r\n level: (process.env.SCAFFOLD_LOG_LEVEL as LogLevel | undefined) ?? 'info',\r\n prefix: '[scaffold]',\r\n});","// src/util/fs-utils.ts\r\n\r\nimport fs from 'fs';\r\nimport path from 'path';\r\n\r\n/**\r\n * Convert any path to a POSIX-style path with forward slashes.\r\n */\r\nexport function toPosixPath(p: string): string {\r\n return p.replace(/\\\\/g, '/');\r\n}\r\n\r\n/**\r\n * Ensure a directory exists (like mkdir -p).\r\n * Returns the absolute path of the directory.\r\n */\r\nexport function ensureDirSync(dirPath: string): string {\r\n if (!fs.existsSync(dirPath)) {\r\n fs.mkdirSync(dirPath, { recursive: true });\r\n }\r\n return dirPath;\r\n}\r\n\r\n/**\r\n * Synchronous check for file or directory existence.\r\n */\r\nexport function existsSync(targetPath: string): boolean {\r\n return fs.existsSync(targetPath);\r\n}\r\n\r\n/**\r\n * Read a file as UTF-8, returning null if it doesn't exist\r\n * or if an error occurs (no exceptions thrown).\r\n */\r\nexport function readFileSafeSync(filePath: string): string | null {\r\n try {\r\n return fs.readFileSync(filePath, 'utf8');\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Write a UTF-8 file, creating parent directories if needed.\r\n */\r\nexport function writeFileSafeSync(filePath: string, contents: string): void {\r\n const dir = path.dirname(filePath);\r\n ensureDirSync(dir);\r\n fs.writeFileSync(filePath, contents, 'utf8');\r\n}\r\n\r\n/**\r\n * Remove a file if it exists. Does nothing on error.\r\n */\r\nexport function removeFileSafeSync(filePath: string): void {\r\n try {\r\n if (fs.existsSync(filePath)) {\r\n fs.unlinkSync(filePath);\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n}\r\n\r\n/**\r\n * Get file stats if they exist, otherwise null.\r\n */\r\nexport function statSafeSync(targetPath: string): fs.Stats | null {\r\n try {\r\n return fs.statSync(targetPath);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Resolve an absolute path from projectRoot + relative path,\r\n * and assert it stays within the project root.\r\n *\r\n * Throws if the resolved path escapes the project root.\r\n */\r\nexport function resolveProjectPath(projectRoot: string, relPath: string): string {\r\n const absRoot = path.resolve(projectRoot);\r\n const absTarget = path.resolve(absRoot, relPath);\r\n\r\n // Normalise for safety check\r\n const rootWithSep = absRoot.endsWith(path.sep) ? absRoot : absRoot + path.sep;\r\n if (!absTarget.startsWith(rootWithSep) && absTarget !== absRoot) {\r\n throw new Error(\r\n `Attempted to resolve path outside project root: ` +\r\n `root=\"${absRoot}\", target=\"${absTarget}\"`,\r\n );\r\n }\r\n\r\n return absTarget;\r\n}\r\n\r\n/**\r\n * Convert an absolute path back to a project-relative path.\r\n * Throws if the path is not under projectRoot.\r\n */\r\nexport function toProjectRelativePath(projectRoot: string, absolutePath: string): string {\r\n const absRoot = path.resolve(projectRoot);\r\n const absTarget = path.resolve(absolutePath);\r\n\r\n const rootWithSep = absRoot.endsWith(path.sep) ? absRoot : absRoot + path.sep;\r\n if (!absTarget.startsWith(rootWithSep) && absTarget !== absRoot) {\r\n throw new Error(\r\n `Path \"${absTarget}\" is not inside project root \"${absRoot}\".`,\r\n );\r\n }\r\n\r\n const rel = path.relative(absRoot, absTarget);\r\n return toPosixPath(rel);\r\n}\r\n\r\n/**\r\n * Check if `target` is inside (or equal to) `base` directory.\r\n */\r\nexport function isSubPath(base: string, target: string): boolean {\r\n const absBase = path.resolve(base);\r\n const absTarget = path.resolve(target);\r\n\r\n const baseWithSep = absBase.endsWith(path.sep) ? absBase : absBase + path.sep;\r\n return absTarget === absBase || absTarget.startsWith(baseWithSep);\r\n}","// src/core/config-loader.ts\r\n\r\nimport fs from 'fs';\r\nimport path from 'path';\r\nimport os from 'os';\r\nimport crypto from 'crypto';\r\nimport { pathToFileURL } from 'url';\r\nimport { transform } from 'esbuild';\r\n\r\nimport type { ScaffoldConfig } from '../schema';\r\nimport { defaultLogger } from '../util/logger';\r\nimport { ensureDirSync } from '../util/fs-utils';\r\n\r\nconst logger = defaultLogger.child('[config]');\r\n\r\nexport interface LoadScaffoldConfigOptions {\r\n /**\r\n * Optional explicit scaffold directory path (absolute or relative to cwd).\r\n * If provided, this overrides config.root for locating the scaffold folder.\r\n */\r\n scaffoldDir?: string;\r\n\r\n /**\r\n * Optional explicit config file path (absolute or relative to cwd).\r\n * If not provided, we look for config.* inside the scaffoldDir.\r\n */\r\n configPath?: string;\r\n}\r\n\r\nexport interface LoadScaffoldConfigResult {\r\n /**\r\n * Parsed scaffold configuration.\r\n */\r\n config: ScaffoldConfig;\r\n\r\n /**\r\n * Absolute path to the scaffold directory (where config & *.txt live).\r\n */\r\n scaffoldDir: string;\r\n\r\n /**\r\n * Effective project root BASE where structures are applied.\r\n * This is derived from config.root + config.base.\r\n */\r\n projectRoot: string;\r\n}\r\n\r\n/**\r\n * Load scaffold configuration based on CWD + optional overrides + config.root/base.\r\n *\r\n * Resolution rules:\r\n * - configRoot:\r\n * - Start from cwd.\r\n * - Apply config.root (if defined) as a path relative to cwd.\r\n * - scaffoldDir:\r\n * - If options.scaffoldDir is provided → use it as-is (resolved from cwd).\r\n * - Else → <configRoot>/scaffold.\r\n * - projectRoot (base):\r\n * - If config.base is defined → resolve relative to configRoot.\r\n * - Else → configRoot.\r\n */\r\nexport async function loadScaffoldConfig(\r\n cwd: string,\r\n options: LoadScaffoldConfigOptions = {},\r\n): Promise<LoadScaffoldConfigResult> {\r\n const absCwd = path.resolve(cwd);\r\n\r\n // First pass: figure out an initial scaffold dir just to locate config.*\r\n const initialScaffoldDir = options.scaffoldDir\r\n ? path.resolve(absCwd, options.scaffoldDir)\r\n : path.join(absCwd, 'scaffold');\r\n\r\n const configPath =\r\n options.configPath ?? resolveConfigPath(initialScaffoldDir);\r\n\r\n // Import config (supports .ts/.tsx via esbuild)\r\n const config = await importConfig(configPath);\r\n\r\n // Now compute configRoot (where scaffold/ lives by default)\r\n let configRoot = absCwd;\r\n if (config.root) {\r\n configRoot = path.resolve(absCwd, config.root);\r\n }\r\n\r\n // Final scaffoldDir (can still be overridden by CLI)\r\n const scaffoldDir = options.scaffoldDir\r\n ? path.resolve(absCwd, options.scaffoldDir)\r\n : path.join(configRoot, 'scaffold');\r\n\r\n // projectRoot (base) is relative to configRoot\r\n const baseRoot = config.base\r\n ? path.resolve(configRoot, config.base)\r\n : configRoot;\r\n\r\n logger.debug(\r\n `Loaded config: configRoot=${configRoot}, baseRoot=${baseRoot}, scaffoldDir=${scaffoldDir}`,\r\n );\r\n\r\n return {\r\n config,\r\n scaffoldDir,\r\n projectRoot: baseRoot,\r\n };\r\n}\r\n\r\nfunction resolveConfigPath(scaffoldDir: string): string {\r\n const candidates = [\r\n 'config.ts',\r\n 'config.mts',\r\n 'config.mjs',\r\n 'config.js',\r\n 'config.cjs',\r\n ];\r\n\r\n for (const file of candidates) {\r\n const full = path.join(scaffoldDir, file);\r\n if (fs.existsSync(full)) {\r\n return full;\r\n }\r\n }\r\n\r\n throw new Error(\r\n `Could not find scaffold config in ${scaffoldDir}. Looked for: ${candidates.join(\r\n ', ',\r\n )}`,\r\n );\r\n}\r\n\r\n/**\r\n * Import a ScaffoldConfig from the given path.\r\n * - For .ts/.tsx we transpile with esbuild to ESM and load from a temp file.\r\n * - For .js/.mjs/.cjs we import directly.\r\n */\r\nasync function importConfig(configPath: string): Promise<ScaffoldConfig> {\r\n const ext = path.extname(configPath).toLowerCase();\r\n\r\n if (ext === '.ts' || ext === '.tsx') {\r\n return importTsConfig(configPath);\r\n }\r\n\r\n const url = pathToFileURL(configPath).href;\r\n const mod = await import(url);\r\n return (mod.default ?? mod) as ScaffoldConfig;\r\n}\r\n\r\n/**\r\n * Transpile a TS config file to ESM with esbuild and import the compiled file.\r\n * We cache based on (path + mtime) so changes invalidate the temp.\r\n */\r\nasync function importTsConfig(configPath: string): Promise<ScaffoldConfig> {\r\n const source = fs.readFileSync(configPath, 'utf8');\r\n const stat = fs.statSync(configPath);\r\n\r\n const hash = crypto\r\n .createHash('sha1')\r\n .update(configPath)\r\n .update(String(stat.mtimeMs))\r\n .digest('hex');\r\n\r\n const tmpDir = path.join(os.tmpdir(), 'timeax-scaffold-config');\r\n ensureDirSync(tmpDir);\r\n\r\n const tmpFile = path.join(tmpDir, `${hash}.mjs`);\r\n\r\n if (!fs.existsSync(tmpFile)) {\r\n const result = await transform(source, {\r\n loader: 'ts',\r\n format: 'esm',\r\n sourcemap: 'inline',\r\n target: 'ESNext',\r\n tsconfigRaw: {\r\n compilerOptions: {\r\n\r\n },\r\n },\r\n });\r\n\r\n fs.writeFileSync(tmpFile, result.code, 'utf8');\r\n }\r\n\r\n const url = pathToFileURL(tmpFile).href;\r\n const mod = await import(url);\r\n return (mod.default ?? mod) as ScaffoldConfig;\r\n}","// src/core/structure-txt.ts\r\n\r\nimport type { StructureEntry, DirEntry, FileEntry } from '../schema';\r\nimport { toPosixPath } from '../util/fs-utils';\r\n\r\ninterface ParsedLine {\r\n lineNo: number;\r\n indentSpaces: number;\r\n rawPath: string;\r\n stub?: string;\r\n include?: string[];\r\n exclude?: string[];\r\n}\r\n\r\n/**\r\n * Parse a single non-empty, non-comment line into a ParsedLine.\r\n * Supports inline annotations:\r\n * - @stub:name\r\n * - @include:pattern,pattern2\r\n * - @exclude:pattern,pattern2\r\n */\r\nfunction parseLine(line: string, lineNo: number): ParsedLine | null {\r\n const match = line.match(/^(\\s*)(.+)$/);\r\n if (!match) return null;\r\n\r\n const indentSpaces = match[1].length;\r\n const rest = match[2].trim();\r\n if (!rest || rest.startsWith('#')) return null;\r\n\r\n const parts = rest.split(/\\s+/);\r\n const pathToken = parts[0];\r\n\r\n let stub: string | undefined;\r\n const include: string[] = [];\r\n const exclude: string[] = [];\r\n\r\n for (const token of parts.slice(1)) {\r\n if (token.startsWith('@stub:')) {\r\n stub = token.slice('@stub:'.length);\r\n } else if (token.startsWith('@include:')) {\r\n const val = token.slice('@include:'.length);\r\n if (val) {\r\n include.push(\r\n ...val\r\n .split(',')\r\n .map((s) => s.trim())\r\n .filter(Boolean),\r\n );\r\n }\r\n } else if (token.startsWith('@exclude:')) {\r\n const val = token.slice('@exclude:'.length);\r\n if (val) {\r\n exclude.push(\r\n ...val\r\n .split(',')\r\n .map((s) => s.trim())\r\n .filter(Boolean),\r\n );\r\n }\r\n }\r\n }\r\n\r\n return {\r\n lineNo,\r\n indentSpaces,\r\n rawPath: pathToken,\r\n stub,\r\n include: include.length ? include : undefined,\r\n exclude: exclude.length ? exclude : undefined,\r\n };\r\n}\r\n\r\n/**\r\n * Convert a structure.txt content into a nested StructureEntry[].\r\n *\r\n * Rules:\r\n * - Indentation is **2 spaces per level** (strict).\r\n * - Indent must be a multiple of 2.\r\n * - You cannot \"skip\" levels (no jumping from level 0 to 2 directly).\r\n * - **Only directories can have children**:\r\n * - If you indent under a file, an error is thrown.\r\n * - Folders must end with \"/\" in the txt; paths are normalized to POSIX.\r\n */\r\nexport function parseStructureText(text: string): StructureEntry[] {\r\n const lines = text.split(/\\r?\\n/);\r\n const parsed: ParsedLine[] = [];\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n const lineNo = i + 1;\r\n const p = parseLine(lines[i], lineNo);\r\n if (p) parsed.push(p);\r\n }\r\n\r\n const rootEntries: StructureEntry[] = [];\r\n\r\n type StackItem = {\r\n level: number;\r\n entry: DirEntry | FileEntry;\r\n isDir: boolean;\r\n };\r\n\r\n const stack: StackItem[] = [];\r\n const INDENT_STEP = 2;\r\n\r\n for (const p of parsed) {\r\n const { indentSpaces, lineNo } = p;\r\n\r\n if (indentSpaces % INDENT_STEP !== 0) {\r\n throw new Error(\r\n `structure.txt: Invalid indent on line ${lineNo}. ` +\r\n `Indent must be multiples of ${INDENT_STEP} spaces.`,\r\n );\r\n }\r\n\r\n const level = indentSpaces / INDENT_STEP;\r\n\r\n // Determine parent level and enforce no skipping\r\n if (level > stack.length) {\r\n // e.g. current stack depth 1, but line level=2+ is invalid\r\n if (level !== stack.length + 1) {\r\n throw new Error(\r\n `structure.txt: Invalid indentation on line ${lineNo}. ` +\r\n `You cannot jump more than one level at a time. ` +\r\n `Previous depth: ${stack.length}, this line depth: ${level}.`,\r\n );\r\n }\r\n }\r\n\r\n // If this line is indented (level > 0), parent must exist and must be dir\r\n if (level > 0) {\r\n const parent = stack[level - 1]; // parent level is (level - 1)\r\n if (!parent) {\r\n throw new Error(\r\n `structure.txt: Indented entry without a parent on line ${lineNo}.`,\r\n );\r\n }\r\n if (!parent.isDir) {\r\n throw new Error(\r\n `structure.txt: Cannot indent under a file on line ${lineNo}. ` +\r\n `Files cannot have children. Parent: \"${parent.entry.path}\".`,\r\n );\r\n }\r\n }\r\n\r\n const isDir = p.rawPath.endsWith('/');\r\n const clean = p.rawPath.replace(/\\/$/, '');\r\n const basePath = toPosixPath(clean);\r\n\r\n // Determine parent based on level\r\n // Pop stack until we are at the correct depth\r\n while (stack.length > level) {\r\n stack.pop();\r\n }\r\n\r\n const parent = stack[stack.length - 1]?.entry as DirEntry | undefined;\r\n const parentPath = parent ? parent.path.replace(/\\/$/, '') : '';\r\n\r\n const fullPath = parentPath\r\n ? `${parentPath}/${basePath}${isDir ? '/' : ''}`\r\n : `${basePath}${isDir ? '/' : ''}`;\r\n\r\n if (isDir) {\r\n const dirEntry: DirEntry = {\r\n type: 'dir',\r\n path: fullPath,\r\n children: [],\r\n ...(p.stub ? { stub: p.stub } : {}),\r\n ...(p.include ? { include: p.include } : {}),\r\n ...(p.exclude ? { exclude: p.exclude } : {}),\r\n };\r\n\r\n if (parent && parent.type === 'dir') {\r\n parent.children = parent.children ?? [];\r\n parent.children.push(dirEntry);\r\n } else if (!parent) {\r\n rootEntries.push(dirEntry);\r\n }\r\n\r\n stack.push({ level, entry: dirEntry, isDir: true });\r\n } else {\r\n const fileEntry: FileEntry = {\r\n type: 'file',\r\n path: fullPath,\r\n ...(p.stub ? { stub: p.stub } : {}),\r\n ...(p.include ? { include: p.include } : {}),\r\n ...(p.exclude ? { exclude: p.exclude } : {}),\r\n };\r\n\r\n if (parent && parent.type === 'dir') {\r\n parent.children = parent.children ?? [];\r\n parent.children.push(fileEntry);\r\n } else if (!parent) {\r\n rootEntries.push(fileEntry);\r\n }\r\n\r\n // files are not added to the stack; they cannot have children\r\n stack.push({ level, entry: fileEntry, isDir: false });\r\n // but next lines at same or lower level will pop correctly\r\n }\r\n }\r\n\r\n return rootEntries;\r\n}","// src/core/resolve-structure.ts\r\n\r\nimport fs from 'fs';\r\nimport path from 'path';\r\nimport type {\r\n ScaffoldConfig,\r\n StructureEntry,\r\n StructureGroupConfig,\r\n} from '../schema';\r\nimport { parseStructureText } from './structure-txt';\r\nimport { defaultLogger } from '../util/logger';\r\n\r\nconst logger = defaultLogger.child('[structure]');\r\n\r\nexport function resolveGroupStructure(\r\n scaffoldDir: string,\r\n group: StructureGroupConfig,\r\n): StructureEntry[] {\r\n if (group.structure && group.structure.length) {\r\n logger.debug(`Using inline structure for group \"${group.name}\"`);\r\n return group.structure;\r\n }\r\n\r\n const fileName = group.structureFile ?? `${group.name}.txt`;\r\n const filePath = path.join(scaffoldDir, fileName);\r\n\r\n if (!fs.existsSync(filePath)) {\r\n throw new Error(\r\n `@timeax/scaffold: Group \"${group.name}\" has no structure. ` +\r\n `Expected file \"${fileName}\" in \"${scaffoldDir}\".`,\r\n );\r\n }\r\n\r\n logger.debug(`Reading structure for group \"${group.name}\" from ${filePath}`);\r\n const raw = fs.readFileSync(filePath, 'utf8');\r\n return parseStructureText(raw);\r\n}\r\n\r\n/**\r\n * Legacy single-structure mode (no groups defined).\r\n */\r\nexport function resolveSingleStructure(\r\n scaffoldDir: string,\r\n config: ScaffoldConfig,\r\n): StructureEntry[] {\r\n if (config.structure && config.structure.length) {\r\n logger.debug('Using inline single structure (no groups)');\r\n return config.structure;\r\n }\r\n\r\n const fileName = config.structureFile ?? 'structure.txt';\r\n const filePath = path.join(scaffoldDir, fileName);\r\n\r\n if (!fs.existsSync(filePath)) {\r\n throw new Error(\r\n `@timeax/scaffold: No structure defined. ` +\r\n `Expected \"${fileName}\" in \"${scaffoldDir}\".`,\r\n );\r\n }\r\n\r\n logger.debug(`Reading single structure from ${filePath}`);\r\n const raw = fs.readFileSync(filePath, 'utf8');\r\n return parseStructureText(raw);\r\n}","// src/core/cache-manager.ts\r\n\r\nimport fs from 'fs';\r\nimport path from 'path';\r\nimport { ensureDirSync, toPosixPath } from '../util/fs-utils';\r\nimport { defaultLogger } from '../util/logger';\r\n\r\nconst logger = defaultLogger.child('[cache]');\r\n\r\nexport interface CacheEntry {\r\n /**\r\n * Path relative to the *project root* (global root), POSIX style.\r\n */\r\n path: string;\r\n\r\n createdAt: string;\r\n sizeAtCreate: number;\r\n createdByStub?: string;\r\n groupName?: string;\r\n groupRoot?: string;\r\n}\r\n\r\nexport interface CacheFile {\r\n version: 1;\r\n entries: Record<string, CacheEntry>;\r\n}\r\n\r\nconst DEFAULT_CACHE: CacheFile = {\r\n version: 1,\r\n entries: {},\r\n};\r\n\r\nexport class CacheManager {\r\n private cache: CacheFile = DEFAULT_CACHE;\r\n\r\n constructor(\r\n private readonly projectRoot: string,\r\n private readonly cacheFileRelPath: string,\r\n ) { }\r\n\r\n private get cachePathAbs(): string {\r\n return path.resolve(this.projectRoot, this.cacheFileRelPath);\r\n }\r\n\r\n load(): void {\r\n const cachePath = this.cachePathAbs;\r\n if (!fs.existsSync(cachePath)) {\r\n this.cache = { ...DEFAULT_CACHE, entries: {} };\r\n return;\r\n }\r\n\r\n try {\r\n const raw = fs.readFileSync(cachePath, 'utf8');\r\n const parsed = JSON.parse(raw) as CacheFile;\r\n if (parsed.version === 1 && parsed.entries) {\r\n this.cache = parsed;\r\n } else {\r\n logger.warn('Cache file version mismatch or invalid, resetting cache.');\r\n this.cache = { ...DEFAULT_CACHE, entries: {} };\r\n }\r\n } catch (err) {\r\n logger.warn('Failed to read cache file, resetting cache.', err);\r\n this.cache = { ...DEFAULT_CACHE, entries: {} };\r\n }\r\n }\r\n\r\n save(): void {\r\n const cachePath = this.cachePathAbs;\r\n const dir = path.dirname(cachePath);\r\n ensureDirSync(dir);\r\n fs.writeFileSync(cachePath, JSON.stringify(this.cache, null, 2), 'utf8');\r\n }\r\n\r\n get(relPath: string): CacheEntry | undefined {\r\n const key = toPosixPath(relPath);\r\n return this.cache.entries[key];\r\n }\r\n\r\n set(entry: CacheEntry): void {\r\n const key = toPosixPath(entry.path);\r\n this.cache.entries[key] = {\r\n ...entry,\r\n path: key,\r\n };\r\n }\r\n\r\n delete(relPath: string): void {\r\n const key = toPosixPath(relPath);\r\n delete this.cache.entries[key];\r\n }\r\n\r\n allPaths(): string[] {\r\n return Object.keys(this.cache.entries);\r\n }\r\n\r\n allEntries(): CacheEntry[] {\r\n return Object.values(this.cache.entries);\r\n }\r\n}","// src/core/hook-runner.ts\r\n\r\nimport { minimatch } from 'minimatch';\r\nimport type {\r\n ScaffoldConfig,\r\n HookContext,\r\n RegularHookKind,\r\n StubHookKind,\r\n StubConfig,\r\n RegularHookConfig,\r\n StubHookConfig,\r\n} from '../schema';\r\n\r\nfunction matchesFilter(\r\n pathRel: string,\r\n cfg: { include?: string[]; exclude?: string[]; files?: string[] },\r\n): boolean {\r\n const { include, exclude, files } = cfg;\r\n\r\n const patterns: string[] = [];\r\n if (include?.length) patterns.push(...include);\r\n if (files?.length) patterns.push(...files);\r\n\r\n if (patterns.length) {\r\n const ok = patterns.some((p) => minimatch(pathRel, p));\r\n if (!ok) return false;\r\n }\r\n\r\n if (exclude?.length) {\r\n const blocked = exclude.some((p) => minimatch(pathRel, p));\r\n if (blocked) return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport class HookRunner {\r\n constructor(private readonly config: ScaffoldConfig) { }\r\n\r\n async runRegular(kind: RegularHookKind, ctx: HookContext): Promise<void> {\r\n const configs: RegularHookConfig[] = this.config.hooks?.[kind] ?? [];\r\n for (const cfg of configs) {\r\n if (!matchesFilter(ctx.targetPath, cfg)) continue;\r\n await cfg.fn(ctx);\r\n }\r\n }\r\n\r\n private getStubConfig(stubName?: string): StubConfig | undefined {\r\n if (!stubName) return undefined;\r\n return this.config.stubs?.[stubName];\r\n }\r\n\r\n async runStub(kind: StubHookKind, ctx: HookContext): Promise<void> {\r\n const stub = this.getStubConfig(ctx.stubName);\r\n if (!stub?.hooks) return;\r\n\r\n const configs: StubHookConfig[] =\r\n kind === 'preStub'\r\n ? stub.hooks.preStub ?? []\r\n : stub.hooks.postStub ?? [];\r\n\r\n for (const cfg of configs) {\r\n if (!matchesFilter(ctx.targetPath, cfg)) continue;\r\n await cfg.fn(ctx);\r\n }\r\n }\r\n\r\n async renderStubContent(ctx: HookContext): Promise<string | undefined> {\r\n const stub = this.getStubConfig(ctx.stubName);\r\n if (!stub?.getContent) return undefined;\r\n return stub.getContent(ctx);\r\n }\r\n}","// src/core/apply-structure.ts\r\n\r\nimport fs from 'fs';\r\nimport path from 'path';\r\nimport type {\r\n ScaffoldConfig,\r\n StructureEntry,\r\n FileEntry,\r\n DirEntry,\r\n HookContext,\r\n} from '../schema';\r\nimport { CacheManager } from './cache-manager';\r\nimport { HookRunner } from './hook-runner';\r\nimport {\r\n ensureDirSync,\r\n statSafeSync,\r\n toProjectRelativePath,\r\n toPosixPath,\r\n} from '../util/fs-utils';\r\nimport type { Logger } from '../util/logger';\r\nimport { defaultLogger } from '../util/logger';\r\n\r\nexport interface InteractiveDeleteParams {\r\n absolutePath: string;\r\n relativePath: string; // project-root relative, POSIX\r\n size: number;\r\n createdByStub?: string;\r\n groupName?: string;\r\n}\r\n\r\nexport interface ApplyOptions {\r\n config: ScaffoldConfig;\r\n\r\n /**\r\n * Global project root for this run.\r\n */\r\n projectRoot: string;\r\n\r\n /**\r\n * Absolute directory where this structure group should be applied.\r\n * For grouped mode, this is projectRoot + group.root.\r\n * For single mode, this will simply be projectRoot.\r\n */\r\n baseDir: string;\r\n\r\n /**\r\n * Which structure entries to apply (already resolved from txt or inline).\r\n */\r\n structure: StructureEntry[];\r\n\r\n cache: CacheManager;\r\n hooks: HookRunner;\r\n\r\n /**\r\n * Optional group metadata (only set for groups).\r\n */\r\n groupName?: string;\r\n groupRoot?: string;\r\n\r\n /**\r\n * Optional override for deletion threshold.\r\n * Falls back to config.sizePromptThreshold or internal default.\r\n */\r\n sizePromptThreshold?: number;\r\n\r\n /**\r\n * Optional interactive delete callback.\r\n * Should ask the user and return 'delete' or 'keep'.\r\n */\r\n interactiveDelete?: (\r\n params: InteractiveDeleteParams,\r\n ) => Promise<'delete' | 'keep'>;\r\n\r\n /**\r\n * Optional logger; defaults to defaultLogger.child('[apply]').\r\n */\r\n logger?: Logger;\r\n}\r\n\r\nexport async function applyStructure(opts: ApplyOptions): Promise<void> {\r\n const {\r\n config,\r\n projectRoot,\r\n baseDir,\r\n structure,\r\n cache,\r\n hooks,\r\n groupName,\r\n groupRoot,\r\n sizePromptThreshold,\r\n interactiveDelete,\r\n } = opts;\r\n\r\n const logger =\r\n opts.logger ?? defaultLogger.child(groupName ? `[apply:${groupName}]` : '[apply]');\r\n\r\n const desiredPaths = new Set<string>(); // project-root relative, POSIX\r\n\r\n const threshold = sizePromptThreshold ?? config.sizePromptThreshold ?? 128 * 1024;\r\n\r\n async function walk(entry: StructureEntry, inheritedStub?: string): Promise<void> {\r\n const effectiveStub = entry.stub ?? inheritedStub;\r\n if (entry.type === 'dir') {\r\n await handleDir(entry as DirEntry, effectiveStub);\r\n } else {\r\n await handleFile(entry as FileEntry, effectiveStub);\r\n }\r\n }\r\n\r\n async function handleDir(entry: DirEntry, inheritedStub?: string): Promise<void> {\r\n const relFromBase = entry.path.replace(/^[./]+/, '');\r\n const absDir = path.resolve(baseDir, relFromBase);\r\n const relFromRoot = toPosixPath(\r\n toProjectRelativePath(projectRoot, absDir),\r\n );\r\n\r\n desiredPaths.add(relFromRoot);\r\n\r\n ensureDirSync(absDir);\r\n\r\n const nextStub = entry.stub ?? inheritedStub;\r\n\r\n if (entry.children) {\r\n for (const child of entry.children) {\r\n // eslint-disable-next-line no-await-in-loop\r\n await walk(child, nextStub);\r\n }\r\n }\r\n }\r\n\r\n async function handleFile(entry: FileEntry, inheritedStub?: string): Promise<void> {\r\n const relFromBase = entry.path.replace(/^[./]+/, '');\r\n const absFile = path.resolve(baseDir, relFromBase);\r\n const relFromRoot = toPosixPath(\r\n toProjectRelativePath(projectRoot, absFile),\r\n );\r\n\r\n desiredPaths.add(relFromRoot);\r\n\r\n const stubName = entry.stub ?? inheritedStub;\r\n\r\n const ctx: HookContext = {\r\n projectRoot,\r\n targetPath: relFromRoot,\r\n absolutePath: absFile,\r\n isDirectory: false,\r\n stubName,\r\n };\r\n\r\n // If file already exists, do not overwrite; just ensure hooks\r\n if (fs.existsSync(absFile)) {\r\n return;\r\n }\r\n\r\n await hooks.runRegular('preCreateFile', ctx);\r\n\r\n const dir = path.dirname(absFile);\r\n ensureDirSync(dir);\r\n\r\n if (stubName) {\r\n await hooks.runStub('preStub', ctx);\r\n }\r\n\r\n let content = '';\r\n const stubContent = await hooks.renderStubContent(ctx);\r\n if (typeof stubContent === 'string') {\r\n content = stubContent;\r\n }\r\n\r\n fs.writeFileSync(absFile, content, 'utf8');\r\n const stats = fs.statSync(absFile);\r\n\r\n cache.set({\r\n path: relFromRoot,\r\n createdAt: new Date().toISOString(),\r\n sizeAtCreate: stats.size,\r\n createdByStub: stubName,\r\n groupName,\r\n groupRoot,\r\n });\r\n\r\n logger.info(`created ${relFromRoot}`);\r\n\r\n if (stubName) {\r\n await hooks.runStub('postStub', ctx);\r\n }\r\n\r\n await hooks.runRegular('postCreateFile', ctx);\r\n }\r\n\r\n // 1) Create/update from structure\r\n for (const entry of structure) {\r\n // eslint-disable-next-line no-await-in-loop\r\n await walk(entry);\r\n }\r\n\r\n // 2) Handle deletions: any cached path not in desiredPaths\r\n for (const cachedPath of cache.allPaths()) {\r\n if (desiredPaths.has(cachedPath)) continue;\r\n\r\n const abs = path.resolve(projectRoot, cachedPath);\r\n const stats = statSafeSync(abs);\r\n\r\n if (!stats) {\r\n cache.delete(cachedPath);\r\n continue;\r\n }\r\n\r\n // Only handle files here; dirs are not tracked in cache.\r\n if (!stats.isFile()) {\r\n cache.delete(cachedPath);\r\n continue;\r\n }\r\n\r\n const entry = cache.get(cachedPath);\r\n const ctx: HookContext = {\r\n projectRoot,\r\n targetPath: cachedPath,\r\n absolutePath: abs,\r\n isDirectory: false,\r\n stubName: entry?.createdByStub,\r\n };\r\n\r\n await hooks.runRegular('preDeleteFile', ctx);\r\n\r\n let shouldDelete = true;\r\n if (stats.size > threshold && interactiveDelete) {\r\n const res = await interactiveDelete({\r\n absolutePath: abs,\r\n relativePath: cachedPath,\r\n size: stats.size,\r\n createdByStub: entry?.createdByStub,\r\n groupName: entry?.groupName,\r\n });\r\n\r\n if (res === 'keep') {\r\n shouldDelete = false;\r\n cache.delete(cachedPath); // user takes ownership\r\n logger.info(`keeping ${cachedPath} (removed from cache)`);\r\n }\r\n }\r\n\r\n if (shouldDelete) {\r\n try {\r\n fs.unlinkSync(abs);\r\n logger.info(`deleted ${cachedPath}`);\r\n } catch (err) {\r\n logger.warn(`failed to delete ${cachedPath}`, err);\r\n }\r\n\r\n cache.delete(cachedPath);\r\n await hooks.runRegular('postDeleteFile', ctx);\r\n }\r\n }\r\n}","// src/core/runner.ts\r\n\r\nimport path from 'path';\r\nimport { loadScaffoldConfig } from './config-loader';\r\nimport {\r\n resolveGroupStructure,\r\n resolveSingleStructure,\r\n} from './resolve-structure';\r\nimport { CacheManager } from './cache-manager';\r\nimport { HookRunner } from './hook-runner';\r\nimport { applyStructure, type InteractiveDeleteParams } from './apply-structure';\r\nimport type { Logger } from '../util/logger';\r\nimport { defaultLogger } from '../util/logger';\r\n\r\nexport interface RunOptions {\r\n /**\r\n * Optional interactive delete callback; if omitted, deletions\r\n * above the size threshold will be skipped (kept + removed from cache).\r\n */\r\n interactiveDelete?: (\r\n params: InteractiveDeleteParams,\r\n ) => Promise<'delete' | 'keep'>;\r\n\r\n /**\r\n * Optional logger override.\r\n */\r\n logger?: Logger;\r\n\r\n /**\r\n * Optional overrides (e.g. allow CLI to point at a different scaffold dir).\r\n */\r\n scaffoldDir?: string;\r\n configPath?: string;\r\n}\r\n\r\n/**\r\n * Run scaffold once for the current working directory.\r\n */\r\nexport async function runOnce(cwd: string, options: RunOptions = {}): Promise<void> {\r\n const logger = options.logger ?? defaultLogger.child('[runner]');\r\n const { config, scaffoldDir, projectRoot } = await loadScaffoldConfig(cwd, {\r\n scaffoldDir: options.scaffoldDir,\r\n configPath: options.configPath,\r\n });\r\n\r\n const cachePath = config.cacheFile ?? '.scaffold-cache.json';\r\n const cache = new CacheManager(projectRoot, cachePath);\r\n cache.load();\r\n\r\n const hooks = new HookRunner(config);\r\n\r\n // Grouped mode\r\n if (config.groups && config.groups.length > 0) {\r\n for (const group of config.groups) {\r\n const groupRootAbs = path.resolve(projectRoot, group.root);\r\n const structure = resolveGroupStructure(scaffoldDir, group);\r\n\r\n const groupLogger = logger.child(`[group:${group.name}]`);\r\n\r\n // eslint-disable-next-line no-await-in-loop\r\n await applyStructure({\r\n config,\r\n projectRoot,\r\n baseDir: groupRootAbs,\r\n structure,\r\n cache,\r\n hooks,\r\n groupName: group.name,\r\n groupRoot: group.root,\r\n interactiveDelete: options.interactiveDelete,\r\n logger: groupLogger,\r\n });\r\n }\r\n } else {\r\n // Single-root mode\r\n const structure = resolveSingleStructure(scaffoldDir, config);\r\n const baseLogger = logger.child('[group:default]');\r\n\r\n await applyStructure({\r\n config,\r\n projectRoot,\r\n baseDir: projectRoot,\r\n structure,\r\n cache,\r\n hooks,\r\n groupName: 'default',\r\n groupRoot: '.',\r\n interactiveDelete: options.interactiveDelete,\r\n logger: baseLogger,\r\n });\r\n }\r\n\r\n cache.save();\r\n}","// src/core/watcher.ts\r\n\r\nimport path from 'path';\r\nimport chokidar from 'chokidar';\r\nimport { runOnce, type RunOptions } from './runner';\r\nimport { defaultLogger, type Logger } from '../util/logger';\r\n\r\nexport interface WatchOptions extends RunOptions {\r\n /**\r\n * Debounce delay in milliseconds between detected changes\r\n * and a scaffold re-run.\r\n *\r\n * Default: 150 ms\r\n */\r\n debounceMs?: number;\r\n\r\n /**\r\n * Optional logger; falls back to defaultLogger.child('[watch]').\r\n */\r\n logger?: Logger;\r\n}\r\n\r\n/**\r\n * Watch the scaffold directory and re-run scaffold on changes.\r\n *\r\n * This watches:\r\n * - scaffold/config.* files\r\n * - scaffold/*.txt files (structures)\r\n *\r\n * CLI can call this when `--watch` is enabled.\r\n */\r\nexport function watchScaffold(cwd: string, options: WatchOptions = {}): void {\r\n const logger = options.logger ?? defaultLogger.child('[watch]');\r\n\r\n const scaffoldDir = options.scaffoldDir\r\n ? path.resolve(cwd, options.scaffoldDir)\r\n : path.resolve(cwd, 'scaffold');\r\n\r\n const debounceMs = options.debounceMs ?? 150;\r\n\r\n logger.info(`Watching scaffold directory: ${scaffoldDir}`);\r\n\r\n let timer: NodeJS.Timeout | undefined;\r\n let running = false;\r\n let pending = false;\r\n\r\n async function run() {\r\n if (running) {\r\n pending = true;\r\n return;\r\n }\r\n running = true;\r\n try {\r\n logger.info('Change detected → running scaffold...');\r\n await runOnce(cwd, {\r\n ...options,\r\n // we already resolved scaffoldDir for watcher; pass it down\r\n scaffoldDir,\r\n });\r\n logger.info('Scaffold run completed.');\r\n } catch (err) {\r\n logger.error('Scaffold run failed:', err);\r\n } finally {\r\n running = false;\r\n if (pending) {\r\n pending = false;\r\n timer = setTimeout(run, debounceMs);\r\n }\r\n }\r\n }\r\n\r\n function scheduleRun() {\r\n if (timer) clearTimeout(timer);\r\n timer = setTimeout(run, debounceMs);\r\n }\r\n\r\n const watcher = chokidar.watch(\r\n [\r\n path.join(scaffoldDir, 'config.*'),\r\n path.join(scaffoldDir, '*.txt'),\r\n ],\r\n {\r\n ignoreInitial: false,\r\n },\r\n );\r\n\r\n watcher\r\n .on('add', (filePath) => {\r\n logger.debug(`File added: ${filePath}`);\r\n scheduleRun();\r\n })\r\n .on('change', (filePath) => {\r\n logger.debug(`File changed: ${filePath}`);\r\n scheduleRun();\r\n })\r\n .on('unlink', (filePath) => {\r\n logger.debug(`File removed: ${filePath}`);\r\n scheduleRun();\r\n })\r\n .on('error', (error) => {\r\n logger.error('Watcher error:', error);\r\n });\r\n\r\n // Initial run\r\n scheduleRun();\r\n}","// src/core/scan-structure.ts\r\n\r\nimport fs from 'fs';\r\nimport path from 'path';\r\nimport { minimatch } from 'minimatch';\r\n\r\nimport {\r\n ScanStructureOptions,\r\n ScanFromConfigOptions,\r\n StructureGroupConfig,\r\n ScaffoldConfig,\r\n} from '../schema';\r\nimport { toPosixPath, ensureDirSync } from '../util/fs-utils';\r\nimport { loadScaffoldConfig } from './config-loader';\r\nimport { defaultLogger } from '../util/logger';\r\n\r\nconst logger = defaultLogger.child('[scan]');\r\n\r\nconst DEFAULT_IGNORE: string[] = [\r\n 'node_modules/**',\r\n '.git/**',\r\n 'dist/**',\r\n 'build/**',\r\n '.turbo/**',\r\n '.next/**',\r\n 'coverage/**',\r\n];\r\n\r\n/**\r\n * Generate a structure.txt-style tree from an existing directory.\r\n *\r\n * Indenting:\r\n * - 2 spaces per level.\r\n * - Directories suffixed with \"/\".\r\n * - No stub/include/exclude annotations are guessed (plain tree).\r\n */\r\nexport function scanDirectoryToStructureText(\r\n rootDir: string,\r\n options: ScanStructureOptions = {},\r\n): string {\r\n const absRoot = path.resolve(rootDir);\r\n const lines: string[] = [];\r\n\r\n const ignorePatterns = options.ignore ?? DEFAULT_IGNORE;\r\n const maxDepth = options.maxDepth ?? Infinity;\r\n\r\n function isIgnored(absPath: string): boolean {\r\n const rel = toPosixPath(path.relative(absRoot, absPath));\r\n if (!rel || rel === '.') return false;\r\n return ignorePatterns.some((pattern) =>\r\n minimatch(rel, pattern, { dot: true }),\r\n );\r\n }\r\n\r\n function walk(currentAbs: string, depth: number) {\r\n if (depth > maxDepth) return;\r\n\r\n let dirents: fs.Dirent[];\r\n try {\r\n dirents = fs.readdirSync(currentAbs, { withFileTypes: true });\r\n } catch {\r\n return;\r\n }\r\n\r\n // Sort: directories first, then files, both alphabetically\r\n dirents.sort((a, b) => {\r\n if (a.isDirectory() && !b.isDirectory()) return -1;\r\n if (!a.isDirectory() && b.isDirectory()) return 1;\r\n return a.name.localeCompare(b.name);\r\n });\r\n\r\n for (const dirent of dirents) {\r\n const name = dirent.name;\r\n const absPath = path.join(currentAbs, name);\r\n\r\n if (isIgnored(absPath)) continue;\r\n\r\n const indent = ' '.repeat(depth);\r\n if (dirent.isDirectory()) {\r\n lines.push(`${indent}${name}/`);\r\n walk(absPath, depth + 1);\r\n } else if (dirent.isFile()) {\r\n lines.push(`${indent}${name}`);\r\n }\r\n // symlinks etc. are skipped for now\r\n }\r\n }\r\n\r\n walk(absRoot, 0);\r\n return lines.join('\\n');\r\n}\r\n\r\n/**\r\n * Result of scanning based on the scaffold config.\r\n *\r\n * You can use `structureFilePath` + `text` to write out group structure files.\r\n */\r\nexport interface ScanFromConfigResult {\r\n groupName: string;\r\n groupRoot: string;\r\n structureFileName: string;\r\n structureFilePath: string;\r\n text: string;\r\n}\r\n\r\n/**\r\n * Scan the project using the scaffold config and its groups.\r\n *\r\n * - If `config.groups` exists and is non-empty:\r\n * - scans each group's `root` (relative to projectRoot)\r\n * - produces text suitable for that group's structure file\r\n * - Otherwise:\r\n * - scans the single `projectRoot` and produces text for a single structure file.\r\n *\r\n * NOTE: This function does NOT write files; it just returns what should be written.\r\n * The CLI (or caller) decides whether/where to save.\r\n */\r\nexport async function scanProjectFromConfig(\r\n cwd: string,\r\n options: ScanFromConfigOptions = {},\r\n): Promise<ScanFromConfigResult[]> {\r\n const { config, scaffoldDir, projectRoot } = await loadScaffoldConfig(cwd, {\r\n scaffoldDir: options.scaffoldDir,\r\n });\r\n\r\n const ignorePatterns = options.ignore ?? DEFAULT_IGNORE;\r\n const maxDepth = options.maxDepth ?? Infinity;\r\n const onlyGroups = options.groups;\r\n\r\n const results: ScanFromConfigResult[] = [];\r\n\r\n function scanGroup(\r\n cfg: ScaffoldConfig,\r\n group: StructureGroupConfig,\r\n ): ScanFromConfigResult {\r\n const rootAbs = path.resolve(projectRoot, group.root);\r\n const text = scanDirectoryToStructureText(rootAbs, {\r\n ignore: ignorePatterns,\r\n maxDepth,\r\n });\r\n\r\n const structureFileName = group.structureFile ?? `${group.name}.txt`;\r\n const structureFilePath = path.join(scaffoldDir, structureFileName);\r\n\r\n return {\r\n groupName: group.name,\r\n groupRoot: group.root,\r\n structureFileName,\r\n structureFilePath,\r\n text,\r\n };\r\n }\r\n\r\n if (config.groups && config.groups.length > 0) {\r\n logger.debug(\r\n `Scanning project from config with ${config.groups.length} group(s).`,\r\n );\r\n\r\n for (const group of config.groups) {\r\n if (onlyGroups && !onlyGroups.includes(group.name)) {\r\n continue;\r\n }\r\n const result = scanGroup(config, group);\r\n results.push(result);\r\n }\r\n } else {\r\n // Single-root mode: scan the whole projectRoot\r\n logger.debug('Scanning project in single-root mode (no groups).');\r\n\r\n const text = scanDirectoryToStructureText(projectRoot, {\r\n ignore: ignorePatterns,\r\n maxDepth,\r\n });\r\n\r\n const structureFileName = config.structureFile ?? 'structure.txt';\r\n const structureFilePath = path.join(scaffoldDir, structureFileName);\r\n\r\n results.push({\r\n groupName: 'default',\r\n groupRoot: '.',\r\n structureFileName,\r\n structureFilePath,\r\n text,\r\n });\r\n }\r\n\r\n return results;\r\n}\r\n\r\n/**\r\n * Convenience helper: write scan results to their structure files.\r\n *\r\n * This will ensure the scaffold directory exists and overwrite existing\r\n * structure files.\r\n */\r\nexport async function writeScannedStructuresFromConfig(\r\n cwd: string,\r\n options: ScanFromConfigOptions = {},\r\n): Promise<void> {\r\n const { scaffoldDir } = await loadScaffoldConfig(cwd, {\r\n scaffoldDir: options.scaffoldDir,\r\n });\r\n\r\n ensureDirSync(scaffoldDir);\r\n\r\n const results = await scanProjectFromConfig(cwd, options);\r\n\r\n for (const result of results) {\r\n fs.writeFileSync(result.structureFilePath, result.text, 'utf8');\r\n logger.info(\r\n `Wrote structure for group \"${result.groupName}\" to ${result.structureFilePath}`,\r\n );\r\n }\r\n}","// src/core/init-scaffold.ts\r\n\r\nimport fs from 'fs';\r\nimport path from 'path';\r\nimport { ensureDirSync } from '../util/fs-utils';\r\nimport { defaultLogger } from '../util/logger';\r\n\r\nconst logger = defaultLogger.child('[init]');\r\n\r\nexport interface InitScaffoldOptions {\r\n /**\r\n * Path to the scaffold directory (relative to cwd).\r\n * Default: \"scaffold\"\r\n */\r\n scaffoldDir?: string;\r\n\r\n /**\r\n * Overwrite existing config/structure files if they already exist.\r\n */\r\n force?: boolean;\r\n\r\n /**\r\n * Name of the config file inside the scaffold directory.\r\n * Default: \"config.ts\"\r\n */\r\n configFileName?: string;\r\n\r\n /**\r\n * Name of the default structure file inside the scaffold directory\r\n * for single-root mode.\r\n * Default: \"structure.txt\"\r\n */\r\n structureFileName?: string;\r\n}\r\n\r\n// src/core/init-scaffold.ts\r\n\r\nconst DEFAULT_CONFIG_TS = `import type { ScaffoldConfig } from '@timeax/scaffold';\r\n\r\nconst config: ScaffoldConfig = {\r\n // Root for resolving the scaffold/ folder & this config file.\r\n // By default, this is the directory where you run \\`scaffold\\`.\r\n // Example:\r\n // root: '.', // scaffold/ at <cwd>/scaffold\r\n // root: 'tools', // scaffold/ at <cwd>/tools/scaffold\r\n // root: '.',\r\n\r\n // Base directory where structures are applied and files/folders are created.\r\n // This is resolved relative to \\`root\\` above. Defaults to the same as root.\r\n // Example:\r\n // base: '.', // apply to <root>\r\n // base: 'src', // apply to <root>/src\r\n // base: '..', // apply to parent of <root>\r\n // base: '.',\r\n\r\n // Cache file path, relative to base.\r\n // cacheFile: '.scaffold-cache.json',\r\n\r\n // --- Single-structure mode (simple) ---\r\n // structureFile: 'structure.txt',\r\n\r\n // --- Grouped mode (uncomment and adjust) ---\r\n // groups: [\r\n // { name: 'app', root: 'app', structureFile: 'app.txt' },\r\n // { name: 'frontend', root: 'resources/js', structureFile: 'frontend.txt' },\r\n // ],\r\n\r\n hooks: {\r\n // preCreateFile: [],\r\n // postCreateFile: [],\r\n // preDeleteFile: [],\r\n // postDeleteFile: [],\r\n },\r\n\r\n stubs: {\r\n // Example:\r\n // page: {\r\n // name: 'page',\r\n // getContent: (ctx) =>\r\n // \\`export default function Page() { return <div>\\${ctx.targetPath}</div>; }\\`,\r\n // },\r\n },\r\n};\r\n\r\nexport default config;\r\n`;\r\n\r\nconst DEFAULT_STRUCTURE_TXT = `# scaffold/structure.txt\r\n# Example structure definition.\r\n# - Indent with 2 spaces per level\r\n# - Directories must end with \"/\"\r\n# - Files do not\r\n# - Lines starting with \"#\" are comments and ignored by parser\r\n\r\n# Example:\r\n# src/\r\n# index.ts\r\n`;\r\n\r\n/**\r\n * Initialize the scaffold directory and basic config/structure files.\r\n *\r\n * - Creates the scaffold directory if it doesn't exist.\r\n * - Writes a default config.ts if missing (or if force = true).\r\n * - Writes a default structure.txt if missing (or if force = true).\r\n */\r\nexport async function initScaffold(\r\n cwd: string,\r\n options: InitScaffoldOptions = {},\r\n): Promise<{\r\n scaffoldDir: string;\r\n configPath: string;\r\n structurePath: string;\r\n created: { config: boolean; structure: boolean };\r\n}> {\r\n const scaffoldDirRel = options.scaffoldDir ?? 'scaffold';\r\n const scaffoldDirAbs = path.resolve(cwd, scaffoldDirRel);\r\n const configFileName = options.configFileName ?? 'config.ts';\r\n const structureFileName = options.structureFileName ?? 'structure.txt';\r\n\r\n ensureDirSync(scaffoldDirAbs);\r\n\r\n const configPath = path.join(scaffoldDirAbs, configFileName);\r\n const structurePath = path.join(scaffoldDirAbs, structureFileName);\r\n\r\n let createdConfig = false;\r\n let createdStructure = false;\r\n\r\n // config.ts\r\n if (fs.existsSync(configPath) && !options.force) {\r\n logger.info(`Config already exists at ${configPath} (use --force to overwrite).`);\r\n } else {\r\n fs.writeFileSync(configPath, DEFAULT_CONFIG_TS, 'utf8');\r\n createdConfig = true;\r\n logger.info(\r\n `${fs.existsSync(configPath) ? 'Overwrote' : 'Created'} config at ${configPath}`,\r\n );\r\n }\r\n\r\n // structure.txt\r\n if (fs.existsSync(structurePath) && !options.force) {\r\n logger.info(\r\n `Structure file already exists at ${structurePath} (use --force to overwrite).`,\r\n );\r\n } else {\r\n fs.writeFileSync(structurePath, DEFAULT_STRUCTURE_TXT, 'utf8');\r\n createdStructure = true;\r\n logger.info(\r\n `${fs.existsSync(structurePath) ? 'Overwrote' : 'Created'} structure file at ${structurePath}`,\r\n );\r\n }\r\n\r\n return {\r\n scaffoldDir: scaffoldDirAbs,\r\n configPath,\r\n structurePath,\r\n created: {\r\n config: createdConfig,\r\n structure: createdStructure,\r\n },\r\n };\r\n}","import readline from 'readline';\r\nimport path from 'path';\r\nimport fs from 'fs';\r\nimport { Command } from 'commander';\r\nimport { runOnce, RunOptions } from '../core/runner';\r\nimport { watchScaffold } from '../core/watcher';\r\nimport {\r\n scanDirectoryToStructureText,\r\n writeScannedStructuresFromConfig,\r\n} from '../core/scan-structure';\r\nimport { initScaffold } from '../core/init-scaffold';\r\nimport {\r\n defaultLogger,\r\n Logger,\r\n type LogLevel,\r\n} from '../util/logger';\r\nimport { ensureDirSync } from '../util/fs-utils';\r\n\r\ninterface BaseCliOptions {\r\n config?: string;\r\n dir?: string;\r\n watch?: boolean;\r\n quiet?: boolean;\r\n debug?: boolean;\r\n}\r\n\r\ninterface ScanCliOptions {\r\n root?: string;\r\n out?: string;\r\n ignore?: string[];\r\n fromConfig?: boolean;\r\n groups?: string[];\r\n}\r\n\r\ninterface InitCliOptions {\r\n force?: boolean;\r\n}\r\n\r\n/**\r\n * Create a logger with the appropriate level from CLI flags.\r\n */\r\nfunction createCliLogger(opts: { quiet?: boolean; debug?: boolean }): Logger {\r\n if (opts.quiet) {\r\n defaultLogger.setLevel('silent');\r\n } else if (opts.debug) {\r\n defaultLogger.setLevel('debug');\r\n }\r\n return defaultLogger.child('[cli]');\r\n}\r\n\r\nfunction askYesNo(question: string): Promise<'delete' | 'keep'> {\r\n const rl = readline.createInterface({\r\n input: process.stdin,\r\n output: process.stdout,\r\n });\r\n\r\n return new Promise((resolve) => {\r\n rl.question(`${question} [y/N] `, (answer) => {\r\n rl.close();\r\n const val = answer.trim().toLowerCase();\r\n if (val === 'y' || val === 'yes') {\r\n resolve('delete');\r\n } else {\r\n resolve('keep');\r\n }\r\n });\r\n });\r\n}\r\n\r\nasync function handleRunCommand(cwd: string, baseOpts: BaseCliOptions) {\r\n const logger = createCliLogger(baseOpts);\r\n\r\n const configPath = baseOpts.config\r\n ? path.resolve(cwd, baseOpts.config)\r\n : undefined;\r\n const scaffoldDir = baseOpts.dir\r\n ? path.resolve(cwd, baseOpts.dir)\r\n : undefined;\r\n\r\n logger.debug(\r\n `Starting scaffold (cwd=${cwd}, config=${configPath ?? 'auto'}, dir=${scaffoldDir ?? 'scaffold/'\r\n }, watch=${baseOpts.watch ? 'yes' : 'no'})`,\r\n );\r\n\r\n const runnerOptions: RunOptions = {\r\n configPath,\r\n scaffoldDir,\r\n logger,\r\n interactiveDelete: async ({\r\n relativePath,\r\n size,\r\n createdByStub,\r\n groupName,\r\n }) => {\r\n const sizeKb = (size / 1024).toFixed(1);\r\n const stubInfo = createdByStub ? ` (stub: ${createdByStub})` : '';\r\n const groupInfo = groupName ? ` [group: ${groupName}]` : '';\r\n const question =\r\n `File \"${relativePath}\"${groupInfo} is ~${sizeKb}KB and no longer in structure${stubInfo}. Delete it?`;\r\n\r\n return askYesNo(question);\r\n },\r\n };\r\n\r\n if (baseOpts.watch) {\r\n // Watch mode – this will not return\r\n watchScaffold(cwd, runnerOptions);\r\n } else {\r\n await runOnce(cwd, runnerOptions);\r\n }\r\n}\r\n\r\nasync function handleScanCommand(\r\n cwd: string,\r\n scanOpts: ScanCliOptions,\r\n baseOpts: BaseCliOptions,\r\n) {\r\n const logger = createCliLogger(baseOpts);\r\n\r\n const useConfigMode =\r\n scanOpts.fromConfig || (!scanOpts.root && !scanOpts.out);\r\n\r\n if (useConfigMode) {\r\n logger.info('Scanning project using scaffold config/groups...');\r\n await writeScannedStructuresFromConfig(cwd, {\r\n ignore: scanOpts.ignore,\r\n groups: scanOpts.groups,\r\n });\r\n return;\r\n }\r\n\r\n // Manual single-root mode\r\n const rootDir = path.resolve(cwd, scanOpts.root ?? '.');\r\n const ignore = scanOpts.ignore ?? [];\r\n\r\n logger.info(`Scanning directory for structure: ${rootDir}`);\r\n const text = scanDirectoryToStructureText(rootDir, {\r\n ignore,\r\n });\r\n\r\n if (scanOpts.out) {\r\n const outPath = path.resolve(cwd, scanOpts.out);\r\n const dir = path.dirname(outPath);\r\n ensureDirSync(dir);\r\n fs.writeFileSync(outPath, text, 'utf8');\r\n logger.info(`Wrote structure to ${outPath}`);\r\n } else {\r\n process.stdout.write(text + '\\n');\r\n }\r\n}\r\n\r\nasync function handleInitCommand(\r\n cwd: string,\r\n initOpts: InitCliOptions,\r\n baseOpts: BaseCliOptions,\r\n) {\r\n const logger = createCliLogger(baseOpts);\r\n\r\n const scaffoldDirRel = baseOpts.dir ?? 'scaffold';\r\n\r\n logger.info(`Initializing scaffold directory at \"${scaffoldDirRel}\"...`);\r\n\r\n const result = await initScaffold(cwd, {\r\n scaffoldDir: scaffoldDirRel,\r\n force: initOpts.force,\r\n });\r\n\r\n logger.info(\r\n `Done. Config: ${result.configPath}, Structure: ${result.structurePath}`,\r\n );\r\n}\r\n\r\nasync function main() {\r\n const cwd = process.cwd();\r\n\r\n const program = new Command();\r\n\r\n program\r\n .name('scaffold')\r\n .description('@timeax/scaffold – structure-based project scaffolding')\r\n // global-ish options used by base + scan + init\r\n .option('-c, --config <path>', 'Path to scaffold config file')\r\n .option('-d, --dir <path>', 'Path to scaffold directory (default: ./scaffold)')\r\n .option('-w, --watch', 'Watch scaffold directory for changes')\r\n .option('--quiet', 'Silence logs')\r\n .option('--debug', 'Enable debug logging');\r\n\r\n // scan subcommand\r\n program\r\n .command('scan')\r\n .description(\r\n 'Generate structure.txt-style output (config-aware by default, or manual root/out)',\r\n )\r\n .option(\r\n '--from-config',\r\n 'Scan based on scaffold config/groups and write structure files into scaffold/ (default if no root/out specified)',\r\n )\r\n .option(\r\n '-r, --root <path>',\r\n 'Root directory to scan (manual mode)',\r\n )\r\n .option(\r\n '-o, --out <path>',\r\n 'Output file path (manual mode)',\r\n )\r\n .option(\r\n '--ignore <patterns...>',\r\n 'Additional glob patterns to ignore (relative to root)',\r\n )\r\n .option(\r\n '--groups <names...>',\r\n 'Limit config-based scanning to specific groups (by name)',\r\n )\r\n .action(async (scanOpts: ScanCliOptions, cmd: Command) => {\r\n const baseOpts = cmd.parent?.opts<BaseCliOptions>() ?? {};\r\n await handleScanCommand(cwd, scanOpts, baseOpts);\r\n });\r\n\r\n // init subcommand\r\n program\r\n .command('init')\r\n .description('Initialize scaffold folder and config/structure files')\r\n .option(\r\n '--force',\r\n 'Overwrite existing config/structure files if they already exist',\r\n )\r\n .action(async (initOpts: InitCliOptions, cmd: Command) => {\r\n const baseOpts = cmd.parent?.opts<BaseCliOptions>() ?? {};\r\n await handleInitCommand(cwd, initOpts, baseOpts);\r\n });\r\n\r\n // Base command: run scaffold once or in watch mode\r\n program.action(async (opts: BaseCliOptions) => {\r\n await handleRunCommand(cwd, opts);\r\n });\r\n\r\n await program.parseAsync(process.argv);\r\n}\r\n\r\n// Run and handle errors\r\nmain().catch((err) => {\r\n defaultLogger.error(err);\r\n process.exit(1);\r\n});"]}
|