feat: документация с алиасом create и корректные примеры

- Обновлены примеры в README и FEATURES с использованием алиаса create
  - Исправлены подсказки help на основной бин gromlab-create
  - Возвращены внутренние вызовы автодополнения на gromlab-create
This commit is contained in:
2026-01-27 15:18:43 +03:00
parent 1a48d6338f
commit b53248e134
5 changed files with 119 additions and 18 deletions

View File

@@ -15,17 +15,28 @@ npm i -g @gromlab/create
## Автодополнение
Сгенерируйте скрипт и подключите его в оболочке:
Установка вместе с автодополнением (одной командой):
**bash**
```bash
gromlab-create completion --shell bash
npm i -g @gromlab/create && create install-autocomplete --shell bash && source ~/.bashrc
```
**zsh**
```bash
npm i -g @gromlab/create && create install-autocomplete --shell zsh && source ~/.zshrc
```
**fish**
```bash
npm i -g @gromlab/create && create install-autocomplete --shell fish && exec fish
```
## Использование
```bash
npx @gromlab/create <шаблон> <имя> [путь] [опции]
create <шаблон> <имя> [путь] [опции]
```
Если `[путь]` не указан, файлы создаются в директории, где запущен CLI.
@@ -34,10 +45,10 @@ npx @gromlab/create <шаблон> <имя> [путь] [опции]
```bash
# Создать компонент из шаблона
npx @gromlab/create component Button
create component Button
# Указать папку вывода позиционно
npx @gromlab/create component Button src/components
create component Button src/components
```
## Шаблоны

View File

@@ -42,9 +42,10 @@
## Автодополнение
- Генерация скрипта автодополнения для bash/zsh/fish: `gromlab-create completion --shell <shell>`.
- Генерация скрипта автодополнения для bash/zsh/fish: `create completion --shell <shell>`.
- Автодополнение доступно только для глобальной установки CLI.
- Автодополнение шаблонов из ближайшей `.templates/` (по дереву вверх) и переменных `--<var>` выбранного шаблона (кроме `name`).
- Команда `install-autocomplete` устанавливает автодополнение в конфигурацию оболочки (bash/zsh) или файл fishcompletions.
## Обновления CLI
@@ -62,8 +63,7 @@
## Бины
- Основной бин: `gromlab-create`.
- Дополнительный алиас: `create`.
- Основной бин: `gromlab-create` (в примерах используется алиас `create`).
## Служебные команды

View File

@@ -1,6 +1,6 @@
{
"name": "@gromlab/create",
"version": "0.1.3",
"version": "0.1.4",
"description": "Template-based file generator CLI",
"license": "MIT",
"publishConfig": {

View File

@@ -3,7 +3,7 @@ import { ParsedArgs } from './types';
export function printHelp() {
const lines = [
'Использование:',
' npx @gromlab/create <шаблон> <имя> [путь] [опции]',
' gromlab-create <шаблон> <имя> [путь] [опции]',
'',
'Аргументы:',
' <шаблон> Имя шаблона',
@@ -12,6 +12,7 @@ export function printHelp() {
'',
'Команды:',
' completion --shell <bash|zsh|fish> Сгенерировать скрипт автодополнения',
' install-autocomplete [--shell <bash|zsh|fish>] Установить автодополнение',
'',
'Опции:',
' --<var> <value> Переменная шаблона (поддерживается любой --key <value>)',
@@ -20,8 +21,8 @@ export function printHelp() {
' -h, --help Показать эту справку',
'',
'Примеры:',
' npx @gromlab/create component Button',
' npx @gromlab/create component Button src/components'
' gromlab-create component Button',
' gromlab-create component Button src/components'
];
console.log(lines.join('\n'));
}

View File

@@ -4,6 +4,8 @@ import { collectTemplateVariables, listTemplateNames } 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);
@@ -205,9 +207,69 @@ function resolveShell(args: string[]): string | undefined {
return candidate;
}
function normalizeShellName(shell?: string): string | undefined {
if (!shell) return undefined;
let normalized = shell.trim().toLowerCase();
if (normalized === 'zh') normalized = 'zsh';
if (normalized === 'bash' || normalized === 'zsh' || normalized === 'fish') return normalized;
return undefined;
}
function detectShellFromEnv(): string | undefined {
const envShell = process.env.SHELL ?? '';
const base = path.basename(envShell).toLowerCase();
if (base === 'bash' || base === 'zsh' || base === 'fish') return base;
return undefined;
}
function printCompletionUsage() {
console.log('Использование:');
console.log(' gromlab-create completion --shell <bash|zsh|fish>');
console.log(' gromlab-create install-autocomplete [--shell <bash|zsh|fish>]');
}
function escapeRegExp(value: string): string {
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function installForBashOrZsh(shell: 'bash' | 'zsh') {
const home = process.env.HOME ?? '';
const rcFile = shell === 'bash'
? path.join(home, '.bashrc')
: path.join(home, '.zshrc');
const sourceLine = `source <(gromlab-create completion --shell ${shell})`;
const block = `${COMPLETION_BLOCK_START}\n${sourceLine}\n${COMPLETION_BLOCK_END}`;
const start = escapeRegExp(COMPLETION_BLOCK_START);
const end = escapeRegExp(COMPLETION_BLOCK_END);
const blockRegex = new RegExp(`${start}[\\s\\S]*?${end}`, 'm');
let content = '';
try {
if (fs.existsSync(rcFile)) {
content = fs.readFileSync(rcFile, 'utf8');
}
} catch {
content = '';
}
if (blockRegex.test(content)) {
content = content.replace(blockRegex, block);
} else {
const prefix = content.length > 0 && !content.endsWith('\n') ? '\n' : '';
content = `${content}${prefix}${block}\n`;
}
fs.writeFileSync(rcFile, content, 'utf8');
console.log(`Автодополнение установлено в ${rcFile}`);
}
function installForFish() {
const home = process.env.HOME ?? '';
const dir = path.join(home, '.config', 'fish', 'completions');
const filePath = path.join(dir, 'gromlab-create.fish');
fs.mkdirSync(dir, { recursive: true });
fs.writeFileSync(filePath, buildFishCompletion(), 'utf8');
console.log(`Автодополнение установлено в ${filePath}`);
}
export function handleInternalCommand(args: string[], cwd: string = process.cwd()): boolean {
@@ -234,19 +296,17 @@ export function handleInternalCommand(args: string[], cwd: string = process.cwd(
return true;
}
const shell = resolveShell(rest);
const shell = normalizeShellName(resolveShell(rest));
if (!shell) {
printCompletionUsage();
process.exitCode = 1;
return true;
}
let normalized = shell.trim().toLowerCase();
if (normalized === 'zh') normalized = 'zsh';
let script = '';
if (normalized === 'bash') script = buildBashCompletion();
if (normalized === 'zsh') script = buildZshCompletion();
if (normalized === 'fish') script = buildFishCompletion();
if (shell === 'bash') script = buildBashCompletion();
if (shell === 'zsh') script = buildZshCompletion();
if (shell === 'fish') script = buildFishCompletion();
if (!script) {
console.error('Неизвестный shell. Доступно: bash, zsh, fish.');
@@ -258,5 +318,34 @@ export function handleInternalCommand(args: string[], cwd: string = process.cwd(
return true;
}
if (command === 'install-autocomplete' || command === 'install-shell') {
if (detectRunMode() !== 'global') {
console.error('Автодополнение доступно только для глобальной установки CLI.');
process.exitCode = 1;
return true;
}
const explicitShell = normalizeShellName(resolveShell(rest));
const shell = explicitShell ?? detectShellFromEnv();
if (!shell) {
console.error('Не удалось определить shell. Укажите --shell <bash|zsh|fish>.');
process.exitCode = 1;
return true;
}
if (shell === 'bash' || shell === 'zsh') {
installForBashOrZsh(shell);
return true;
}
if (shell === 'fish') {
installForFish();
return true;
}
console.error('Неизвестный shell. Доступно: bash, zsh, fish.');
process.exitCode = 1;
return true;
}
return false;
}