From 96d68c5a63602ae35ab8a24c128a3304b5267b99 Mon Sep 17 00:00:00 2001 From: "S.Gromov" Date: Thu, 2 Apr 2026 18:17:32 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BF=D1=80=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC?= =?UTF-8?q?=D0=BD=D1=8B=D0=B9=20API=20=D0=B4=D0=BB=D1=8F=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BA=D0=B0=D0=BA=20=D0=B1=D0=B8=D0=B1=D0=BB=D0=B8?= =?UTF-8?q?=D0=BE=D1=82=D0=B5=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - создан src/index.ts с реэкспортом 14 чистых функций и типов - перенесён findNearestTemplatesDir из completion.ts в templateUtils.ts - обновлён package.json: main → dist/index.js, добавлено поле types - добавлен declaration: true в tsconfig.json для генерации .d.ts - документирован API в README.md и README_RU.md - версия поднята до 0.2.0 --- README.md | 24 ++++++++++++++++++++++++ README_RU.md | 24 ++++++++++++++++++++++++ package.json | 5 +++-- src/completion.ts | 20 +------------------- src/index.ts | 21 +++++++++++++++++++++ src/templateUtils.ts | 18 ++++++++++++++++++ tsconfig.json | 1 + 7 files changed, 92 insertions(+), 21 deletions(-) create mode 100644 src/index.ts diff --git a/README.md b/README.md index 8ac6fe1..8c15041 100644 --- a/README.md +++ b/README.md @@ -117,3 +117,27 @@ export const {{name.pascalCase}} = () => { | `--overwrite` | Overwrite existing files | | `--skip-update` | Skip CLI update check | | `-- ` | Custom template variable | + +## Programmatic API + +The package can be used as a library: + +```typescript +import { buildPlan, writePlan, collectTemplateVariables } from '@gromlab/create'; +``` + +| Function | Description | +|---|---| +| `renderTemplate(input, vars)` | Substitutes variables and modifiers in a string | +| `collectTemplateVariables(templateDir)` | Collects all variable names from a template | +| `listTemplateNames(templatesDir)` | Lists available templates (subdirectories) | +| `findNearestTemplatesDir(startDir)` | Walks up the directory tree looking for `.templates` | +| `readDirRecursive(dir)` | Recursive list of all files in a directory | +| `resolveTemplateContext(templatesDir, name, vars)` | Validates template and variables | +| `buildPlan(templateDir, outDir, vars, files)` | Builds generation plan (source → target) | +| `writePlan(plan, vars, overwrite)` | Writes files to disk according to the plan | +| `getCollisions(plan)` | Lists plan files that already exist on disk | +| `getExistingDirs(outDir, dirs)` | Checks which directories already exist | +| `getTopLevelDirs(outDir, plan)` | Top-level directories from the plan | +| `getRoots(outDir, plan)` | Root paths for summary output | +| `CASE_MODIFIERS` | Case modifier functions dictionary | diff --git a/README_RU.md b/README_RU.md index 2bc13e4..5f95b01 100644 --- a/README_RU.md +++ b/README_RU.md @@ -117,3 +117,27 @@ export const {{name.pascalCase}} = () => { | `--overwrite` | Перезаписать существующие файлы | | `--skip-update` | Не проверять обновления CLI | | `--<переменная> <значение>` | Произвольная переменная шаблона | + +## Программный API + +Пакет можно использовать как библиотеку: + +```typescript +import { buildPlan, writePlan, collectTemplateVariables } from '@gromlab/create'; +``` + +| Функция | Назначение | +|---|---| +| `renderTemplate(input, vars)` | Подставляет переменные и модификаторы в строку | +| `collectTemplateVariables(templateDir)` | Собирает все имена переменных из шаблона | +| `listTemplateNames(templatesDir)` | Список доступных шаблонов (подпапки) | +| `findNearestTemplatesDir(startDir)` | Ищет `.templates` вверх по дереву каталогов | +| `readDirRecursive(dir)` | Рекурсивный список всех файлов в каталоге | +| `resolveTemplateContext(templatesDir, name, vars)` | Валидация шаблона и переменных | +| `buildPlan(templateDir, outDir, vars, files)` | Построение плана генерации (source → target) | +| `writePlan(plan, vars, overwrite)` | Запись файлов на диск по плану | +| `getCollisions(plan)` | Список файлов из плана, которые уже существуют | +| `getExistingDirs(outDir, dirs)` | Проверка существующих директорий | +| `getTopLevelDirs(outDir, plan)` | Директории верхнего уровня из плана | +| `getRoots(outDir, plan)` | Корневые пути для итогового вывода | +| `CASE_MODIFIERS` | Словарь модификаторов регистра | diff --git a/package.json b/package.json index 7fe6879..12b245e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@gromlab/create", - "version": "0.1.7", + "version": "0.2.0", "description": "Template-based file generator CLI", "author": "Gromov Sergei", "license": "MIT", @@ -27,7 +27,8 @@ "gromlab-create": "dist/cli.js", "create": "dist/cli.js" }, - "main": "dist/cli.js", + "main": "dist/index.js", + "types": "dist/index.d.ts", "files": [ "dist" ], diff --git a/src/completion.ts b/src/completion.ts index e42f445..fa557e0 100644 --- a/src/completion.ts +++ b/src/completion.ts @@ -1,30 +1,12 @@ import * as fs from 'fs'; import * as path from 'path'; -import { collectTemplateVariables, listTemplateNames } from './templateUtils'; +import { collectTemplateVariables, listTemplateNames, findNearestTemplatesDir } from './templateUtils'; import { detectRunMode } from './runtime'; const BIN_NAMES = ['gromlab-create', 'create']; const COMPLETION_BLOCK_START = '# gromlab-create completion start'; const COMPLETION_BLOCK_END = '# gromlab-create completion end'; -function findNearestTemplatesDir(startDir: string): string | undefined { - let current = path.resolve(startDir); - while (true) { - const candidate = path.join(current, '.templates'); - try { - if (fs.existsSync(candidate) && fs.statSync(candidate).isDirectory()) { - return candidate; - } - } catch { - // ignore errors and keep walking up - } - const parent = path.dirname(current); - if (parent === current) break; - current = parent; - } - return undefined; -} - function listTemplates(cwd: string): string[] { const dir = findNearestTemplatesDir(cwd); try { diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..d0ddebf --- /dev/null +++ b/src/index.ts @@ -0,0 +1,21 @@ +// Программный API для @gromlab/create +// CLI точка входа остаётся в cli.ts (bin) + +// Генерация +export { buildPlan, writePlan, getCollisions, getExistingDirs, getTopLevelDirs, getRoots } from './plan'; + +// Шаблоны +export { + renderTemplate, + collectTemplateVariables, + readDirRecursive, + listTemplateNames, + findNearestTemplatesDir, + CASE_MODIFIERS, +} from './templateUtils'; + +// Валидация +export { resolveTemplateContext, normalizeArgs } from './validation'; + +// Типы +export type { PlanItem, TemplateContext, ValidationError, ParsedArgs } from './types'; diff --git a/src/templateUtils.ts b/src/templateUtils.ts index 4b59aaa..1bca227 100644 --- a/src/templateUtils.ts +++ b/src/templateUtils.ts @@ -70,3 +70,21 @@ export function listTemplateNames(templatesDir: string): string[] { const entries = fs.readdirSync(templatesDir, { withFileTypes: true }); return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(); } + +export function findNearestTemplatesDir(startDir: string): string | undefined { + let current = path.resolve(startDir); + while (true) { + const candidate = path.join(current, '.templates'); + try { + if (fs.existsSync(candidate) && fs.statSync(candidate).isDirectory()) { + return candidate; + } + } catch { + // ignore errors and keep walking up + } + const parent = path.dirname(current); + if (parent === current) break; + current = parent; + } + return undefined; +} diff --git a/tsconfig.json b/tsconfig.json index 4ce4240..89b864b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "outDir": "dist", "rootDir": "src", "strict": true, + "declaration": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true