@lenne.tech/cli 1.5.0 → 1.6.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/README.md +30 -0
- package/bin/postinstall.js +156 -0
- package/build/cli.js +11 -1
- package/build/commands/blocks/add.js +28 -306
- package/build/commands/blocks/blocks.js +2 -2
- package/build/commands/claude/claude.js +2 -2
- package/build/commands/cli/cli.js +2 -2
- package/build/commands/cli/create.js +69 -21
- package/build/commands/cli/rename.js +11 -5
- package/build/commands/completion.js +311 -0
- package/build/commands/components/add.js +25 -219
- package/build/commands/components/components.js +2 -2
- package/build/commands/config/help.js +5 -2
- package/build/commands/config/init.js +20 -5
- package/build/commands/config/show.js +4 -1
- package/build/commands/config/validate.js +27 -2
- package/build/commands/deployment/create.js +18 -5
- package/build/commands/deployment/deployment.js +2 -2
- package/build/commands/docs/open.js +4 -1
- package/build/commands/doctor.js +285 -0
- package/build/commands/frontend/angular.js +88 -28
- package/build/commands/frontend/nuxt.js +2 -1
- package/build/commands/fullstack/init.js +58 -19
- package/build/commands/git/clean.js +60 -11
- package/build/commands/git/clear.js +17 -11
- package/build/commands/git/create.js +51 -10
- package/build/commands/git/force-pull.js +42 -15
- package/build/commands/git/get.js +14 -15
- package/build/commands/git/install-scripts.js +6 -6
- package/build/commands/git/rebase.js +40 -12
- package/build/commands/git/rename.js +33 -13
- package/build/commands/git/reset.js +48 -13
- package/build/commands/git/squash.js +67 -26
- package/build/commands/git/undo.js +33 -13
- package/build/commands/git/update.js +59 -6
- package/build/commands/history.js +75 -0
- package/build/commands/mongodb/collection-export.js +2 -2
- package/build/commands/mongodb/mongodb.js +2 -2
- package/build/commands/mongodb/s3-restore.js +2 -2
- package/build/commands/npm/reinit.js +11 -12
- package/build/commands/npm/update.js +6 -2
- package/build/commands/qdrant/delete.js +6 -2
- package/build/commands/qdrant/qdrant.js +2 -2
- package/build/commands/qdrant/stats.js +5 -2
- package/build/commands/redis/redis.js +2 -2
- package/build/commands/server/add-property.js +8 -12
- package/build/commands/server/create-secret.js +6 -3
- package/build/commands/server/create.js +39 -21
- package/build/commands/server/module.js +22 -16
- package/build/commands/server/object.js +7 -11
- package/build/commands/server/set-secrets.js +6 -3
- package/build/commands/server/test.js +3 -3
- package/build/commands/starter/chrome-extension.js +3 -3
- package/build/commands/status.js +198 -0
- package/build/commands/templates/list.js +107 -0
- package/build/commands/templates/llm.js +8 -3
- package/build/commands/templates/templates.js +2 -2
- package/build/commands/tools/jwt-read.js +2 -2
- package/build/commands/tools/regex.js +5 -2
- package/build/commands/typescript/create.js +84 -21
- package/build/commands/typescript/playground.js +5 -2
- package/build/extensions/config.js +37 -1
- package/build/extensions/git.js +57 -2
- package/build/extensions/history.js +118 -0
- package/build/extensions/logger.js +189 -0
- package/build/lib/nuxt-base-components.js +249 -0
- package/build/lib/validation.js +204 -0
- package/build/templates/completion/bash.sh.ejs +92 -0
- package/build/templates/completion/fish.sh.ejs +77 -0
- package/build/templates/completion/zsh.sh.ejs +119 -0
- package/docs/commands.md +464 -14
- package/docs/lt.config.md +138 -8
- package/package.json +16 -14
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.copyComposable = copyComposable;
|
|
13
|
+
exports.copyFile = copyFile;
|
|
14
|
+
exports.getConfig = getConfig;
|
|
15
|
+
exports.getConfigForFile = getConfigForFile;
|
|
16
|
+
exports.getFileInfo = getFileInfo;
|
|
17
|
+
exports.installPackage = installPackage;
|
|
18
|
+
exports.processConfig = processConfig;
|
|
19
|
+
/**
|
|
20
|
+
* Shared utilities for blocks and components commands
|
|
21
|
+
* These functions handle downloading and installing Nuxt base components from GitHub
|
|
22
|
+
*/
|
|
23
|
+
const axios_1 = require("axios");
|
|
24
|
+
const fs = require("fs");
|
|
25
|
+
const glob = require("glob");
|
|
26
|
+
const gluegun_1 = require("gluegun");
|
|
27
|
+
const path = require("path");
|
|
28
|
+
const GITHUB_BASE_URL = 'https://raw.githubusercontent.com/lenneTech/nuxt-base-components/main';
|
|
29
|
+
const GITHUB_API_URL = 'https://api.github.com/repos/lenneTech/nuxt-base-components/contents';
|
|
30
|
+
/**
|
|
31
|
+
* Copy a composable from GitHub to the local composables directory
|
|
32
|
+
*/
|
|
33
|
+
function copyComposable(composable_1, toolbox_1) {
|
|
34
|
+
return __awaiter(this, arguments, void 0, function* (composable, toolbox, noConfirm = false) {
|
|
35
|
+
const { print, prompt } = toolbox;
|
|
36
|
+
const apiUrl = `${GITHUB_BASE_URL}/composables/${composable}.ts`;
|
|
37
|
+
const response = yield axios_1.default.get(apiUrl);
|
|
38
|
+
if (response.status === 200) {
|
|
39
|
+
const sourceCode = response.data;
|
|
40
|
+
const cwd = process.cwd();
|
|
41
|
+
let targetDirectory;
|
|
42
|
+
if (fs.existsSync(path.resolve(cwd, 'composables'))) {
|
|
43
|
+
targetDirectory = path.resolve(cwd, 'composables');
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const directories = glob.sync('*/composables', { cwd });
|
|
47
|
+
if (directories.length > 0) {
|
|
48
|
+
targetDirectory = path.join(cwd, directories[0]);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
targetDirectory = cwd;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Check if composable already exists
|
|
55
|
+
if (fs.existsSync(path.join(targetDirectory, `${composable}.ts`))) {
|
|
56
|
+
print.info(`The composable ${composable} already exists`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (!noConfirm) {
|
|
60
|
+
const confirmAdd = yield prompt.confirm(`The composable ${composable} is required. Would you like to add it?`);
|
|
61
|
+
if (!confirmAdd) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const targetPath = path.join(targetDirectory, `${composable}.ts`);
|
|
66
|
+
const spinner = print.spin(`Copy the composable ${composable} to ${targetPath}...`);
|
|
67
|
+
fs.writeFileSync(targetPath, sourceCode);
|
|
68
|
+
spinner.succeed(`The composable ${composable} was successfully copied to ${targetPath}`);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
print.error(`Error retrieving the file from GitHub: ${response.statusText}`);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Copy a file (block or component) from GitHub to local directory
|
|
77
|
+
*/
|
|
78
|
+
function copyFile(file_1, toolbox_1, type_1) {
|
|
79
|
+
return __awaiter(this, arguments, void 0, function* (file, toolbox, type, noConfirm = false) {
|
|
80
|
+
const { print } = toolbox;
|
|
81
|
+
const apiUrl = `${GITHUB_BASE_URL}/${type}/${file.name}`;
|
|
82
|
+
const targetDirName = type === 'blocks' ? 'pages' : 'components';
|
|
83
|
+
const config = yield getConfigForFile(file.name, toolbox, type === 'blocks' ? 'block' : 'component');
|
|
84
|
+
if (config) {
|
|
85
|
+
yield processConfig(config, toolbox, type, noConfirm);
|
|
86
|
+
}
|
|
87
|
+
const compSpinner = print.spin(`Load ${type.slice(0, -1)} ${file.name} from GitHub...`);
|
|
88
|
+
const response = yield axios_1.default.get(apiUrl);
|
|
89
|
+
compSpinner.succeed(`${type === 'blocks' ? 'Block' : 'Component'} ${file.name} successfully loaded from GitHub`);
|
|
90
|
+
if (response.status === 200) {
|
|
91
|
+
const sourceCode = response.data;
|
|
92
|
+
const cwd = process.cwd();
|
|
93
|
+
let targetDirectory;
|
|
94
|
+
if (fs.existsSync(path.resolve(cwd, targetDirName))) {
|
|
95
|
+
targetDirectory = path.resolve(cwd, targetDirName);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
const directories = glob.sync(`*/${targetDirName}`, { cwd });
|
|
99
|
+
if (directories.length > 0) {
|
|
100
|
+
targetDirectory = path.join(cwd, directories[0]);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
targetDirectory = cwd;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
let targetName = file.name;
|
|
107
|
+
if (type === 'blocks') {
|
|
108
|
+
targetName = file.name
|
|
109
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
110
|
+
.toLowerCase()
|
|
111
|
+
.replace(/^block-/, '');
|
|
112
|
+
}
|
|
113
|
+
const targetPath = path.join(targetDirectory, targetName);
|
|
114
|
+
// Check if file already exists
|
|
115
|
+
if (fs.existsSync(targetPath)) {
|
|
116
|
+
print.info(`The ${type.slice(0, -1)} ${file.name} already exists`);
|
|
117
|
+
return targetPath;
|
|
118
|
+
}
|
|
119
|
+
if (!fs.existsSync(targetDirectory)) {
|
|
120
|
+
const targetDirSpinner = print.spin('Creating the target directory...');
|
|
121
|
+
fs.mkdirSync(targetDirectory, { recursive: true });
|
|
122
|
+
targetDirSpinner.succeed();
|
|
123
|
+
}
|
|
124
|
+
if (file.type === 'dir' || file.name.split('/').length > 1) {
|
|
125
|
+
const dirName = file.name.split('/')[0];
|
|
126
|
+
const dirPath = path.join(targetDirectory, dirName);
|
|
127
|
+
if (!fs.existsSync(dirPath)) {
|
|
128
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const spinner = print.spin(`Copy the ${type.slice(0, -1)} ${targetName} to ${targetPath}...`);
|
|
132
|
+
fs.writeFileSync(targetPath, sourceCode);
|
|
133
|
+
spinner.succeed(`The ${type.slice(0, -1)} ${targetName} was successfully copied to ${targetPath}`);
|
|
134
|
+
return targetPath;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
throw new Error(`Error retrieving the file from GitHub: ${response.statusText}`);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get the config.json from the nuxt-base-components repository
|
|
143
|
+
*/
|
|
144
|
+
function getConfig() {
|
|
145
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
146
|
+
const githubApiUrl = `${GITHUB_BASE_URL}/config.json`;
|
|
147
|
+
const response = yield axios_1.default.get(githubApiUrl);
|
|
148
|
+
if (response.status === 200) {
|
|
149
|
+
return response.data;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
throw new Error(`Error when retrieving the configuration from GitHub: ${response.statusText}`);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get configuration for a specific block or component
|
|
158
|
+
*/
|
|
159
|
+
function getConfigForFile(fileName, toolbox, type) {
|
|
160
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
161
|
+
const { print } = toolbox;
|
|
162
|
+
const configSpinner = print.spin(`Checking the config for ${type}...`);
|
|
163
|
+
const data = yield getConfig();
|
|
164
|
+
const name = fileName.split('.').slice(0, -1).join('.');
|
|
165
|
+
const rootName = name.split('/')[0];
|
|
166
|
+
configSpinner.succeed(`Config for ${rootName} loaded successfully`);
|
|
167
|
+
return data.config[rootName] || {};
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Get file info from GitHub API for blocks or components
|
|
172
|
+
*/
|
|
173
|
+
function getFileInfo(type, subPath) {
|
|
174
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
175
|
+
const githubApiUrl = `${GITHUB_API_URL}/${type}${subPath ? `/${subPath}` : ''}`;
|
|
176
|
+
const response = yield axios_1.default.get(githubApiUrl);
|
|
177
|
+
if (response.status === 200) {
|
|
178
|
+
return response.data.map((file) => ({
|
|
179
|
+
name: file.name,
|
|
180
|
+
type: file.type,
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
throw new Error(`Error when retrieving the file list from GitHub: ${response.statusText}`);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Install an npm package if not already installed
|
|
190
|
+
*/
|
|
191
|
+
function installPackage(packageName_1, toolbox_1) {
|
|
192
|
+
return __awaiter(this, arguments, void 0, function* (packageName, toolbox, noConfirm = false) {
|
|
193
|
+
const { print, prompt, system } = toolbox;
|
|
194
|
+
const nameWithoutVersion = packageName.split('@')[0] || packageName;
|
|
195
|
+
const packageJsonPath = path.resolve(process.cwd(), 'package.json');
|
|
196
|
+
const packageJson = gluegun_1.filesystem.read(packageJsonPath, 'json');
|
|
197
|
+
const isInstalled = (packageJson.dependencies && packageJson.dependencies[nameWithoutVersion])
|
|
198
|
+
|| (packageJson.devDependencies && packageJson.devDependencies[nameWithoutVersion]);
|
|
199
|
+
if (!isInstalled) {
|
|
200
|
+
if (!noConfirm) {
|
|
201
|
+
const confirmInstall = yield prompt.confirm(`The npm package ${nameWithoutVersion} is required. Would you like to install it?`);
|
|
202
|
+
if (!confirmInstall) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const installSpinner = print.spin(`Install npm package ${nameWithoutVersion}...`);
|
|
207
|
+
yield system.run(`npm install ${packageName} --save-exact`);
|
|
208
|
+
installSpinner.succeed(`npm package ${nameWithoutVersion} successfully installed`);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
print.info(`npm package ${nameWithoutVersion} is already installed`);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Process config dependencies (npm packages, composables, components)
|
|
217
|
+
*/
|
|
218
|
+
function processConfig(config_1, toolbox_1, type_1) {
|
|
219
|
+
return __awaiter(this, arguments, void 0, function* (config, toolbox, type, noConfirm = false) {
|
|
220
|
+
if (config === null || config === void 0 ? void 0 : config.npm) {
|
|
221
|
+
const npmPackages = config.npm;
|
|
222
|
+
for (const npmPackage of npmPackages) {
|
|
223
|
+
yield installPackage(npmPackage, toolbox, noConfirm);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (config === null || config === void 0 ? void 0 : config.composables) {
|
|
227
|
+
const composables = config.composables;
|
|
228
|
+
for (const composable of composables) {
|
|
229
|
+
yield copyComposable(composable, toolbox, noConfirm);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (config === null || config === void 0 ? void 0 : config.components) {
|
|
233
|
+
const components = config.components;
|
|
234
|
+
for (const component of components) {
|
|
235
|
+
if (component.endsWith('/*')) {
|
|
236
|
+
const folderName = component.split('/')[0];
|
|
237
|
+
const directoryFiles = yield getFileInfo('components', folderName);
|
|
238
|
+
for (const file of directoryFiles) {
|
|
239
|
+
yield copyFile({ name: `${folderName}/${file.name}`, type: 'dir' }, toolbox, 'components', noConfirm);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
yield copyFile({ name: `${component}.vue`, type: 'file' }, toolbox, 'components', noConfirm);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnV4dC1iYXNlLWNvbXBvbmVudHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbGliL251eHQtYmFzZS1jb21wb25lbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBdUJBLHdDQThDQztBQUtELDRCQXlFQztBQUtELDhCQVNDO0FBS0QsNENBY0M7QUFLRCxrQ0FlQztBQUtELHdDQThCQztBQUtELHNDQW1DQztBQW5SRDs7O0dBR0c7QUFDSCxpQ0FBMEI7QUFDMUIseUJBQXlCO0FBQ3pCLDZCQUE2QjtBQUM3QixxQ0FBcUM7QUFDckMsNkJBQTZCO0FBSTdCLE1BQU0sZUFBZSxHQUFHLHVFQUF1RSxDQUFDO0FBQ2hHLE1BQU0sY0FBYyxHQUFHLHNFQUFzRSxDQUFDO0FBTzlGOztHQUVHO0FBQ0gsU0FBc0IsY0FBYzt5REFDbEMsVUFBa0IsRUFDbEIsT0FBK0IsRUFDL0IsU0FBUyxHQUFHLEtBQUs7UUFFakIsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUM7UUFDbEMsTUFBTSxNQUFNLEdBQUcsR0FBRyxlQUFlLGdCQUFnQixVQUFVLEtBQUssQ0FBQztRQUNqRSxNQUFNLFFBQVEsR0FBRyxNQUFNLGVBQUssQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFekMsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQzVCLE1BQU0sVUFBVSxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUM7WUFDakMsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQzFCLElBQUksZUFBdUIsQ0FBQztZQUU1QixJQUFJLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsYUFBYSxDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUNwRCxlQUFlLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUs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
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Input validation utilities for CLI commands
|
|
4
|
+
* Provides consistent validation patterns across all commands
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.ValidationRules = void 0;
|
|
8
|
+
exports.sanitizeInput = sanitizeInput;
|
|
9
|
+
exports.sanitizePath = sanitizePath;
|
|
10
|
+
exports.toCamelCase = toCamelCase;
|
|
11
|
+
exports.toKebabCase = toKebabCase;
|
|
12
|
+
exports.toPascalCase = toPascalCase;
|
|
13
|
+
exports.validateBranchName = validateBranchName;
|
|
14
|
+
exports.validateClassName = validateClassName;
|
|
15
|
+
exports.validateEmail = validateEmail;
|
|
16
|
+
exports.validateFileName = validateFileName;
|
|
17
|
+
exports.validateKebabCase = validateKebabCase;
|
|
18
|
+
exports.validateLength = validateLength;
|
|
19
|
+
exports.validateNpmPackage = validateNpmPackage;
|
|
20
|
+
exports.validatePattern = validatePattern;
|
|
21
|
+
exports.validatePropertyName = validatePropertyName;
|
|
22
|
+
exports.validateRequired = validateRequired;
|
|
23
|
+
/**
|
|
24
|
+
* Validation rules for common input types
|
|
25
|
+
*/
|
|
26
|
+
exports.ValidationRules = {
|
|
27
|
+
/**
|
|
28
|
+
* Valid branch name pattern (git-compatible)
|
|
29
|
+
*/
|
|
30
|
+
branchName: /^(?![-./])(?!.*[-./]$)(?!.*[-./]{2})[a-zA-Z0-9._/-]+$/,
|
|
31
|
+
/**
|
|
32
|
+
* Valid module/class name (PascalCase)
|
|
33
|
+
*/
|
|
34
|
+
className: /^[A-Z][a-zA-Z0-9]*$/,
|
|
35
|
+
/**
|
|
36
|
+
* Valid email address pattern
|
|
37
|
+
*/
|
|
38
|
+
email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
39
|
+
/**
|
|
40
|
+
* Valid file/directory name (no special chars)
|
|
41
|
+
*/
|
|
42
|
+
fileName: /^[a-zA-Z0-9._-]+$/,
|
|
43
|
+
/**
|
|
44
|
+
* Valid kebab-case name
|
|
45
|
+
*/
|
|
46
|
+
kebabCase: /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/,
|
|
47
|
+
/**
|
|
48
|
+
* Valid npm package name
|
|
49
|
+
*/
|
|
50
|
+
npmPackage: /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,
|
|
51
|
+
/**
|
|
52
|
+
* Valid property name (camelCase)
|
|
53
|
+
*/
|
|
54
|
+
propertyName: /^[a-z][a-zA-Z0-9]*$/,
|
|
55
|
+
/**
|
|
56
|
+
* Valid semver version
|
|
57
|
+
*/
|
|
58
|
+
semver: /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/,
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Sanitize input by removing potentially dangerous characters
|
|
62
|
+
*/
|
|
63
|
+
function sanitizeInput(input) {
|
|
64
|
+
if (!input)
|
|
65
|
+
return '';
|
|
66
|
+
return input
|
|
67
|
+
.trim()
|
|
68
|
+
// Remove shell special characters
|
|
69
|
+
.replace(/[;&|`$(){}[\]<>\\'"]/g, '')
|
|
70
|
+
// Remove control characters
|
|
71
|
+
.replace(/[\x00-\x1F\x7F]/g, '')
|
|
72
|
+
// Collapse multiple spaces
|
|
73
|
+
.replace(/\s+/g, ' ');
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Sanitize a file path to prevent directory traversal
|
|
77
|
+
*/
|
|
78
|
+
function sanitizePath(input) {
|
|
79
|
+
if (!input)
|
|
80
|
+
return '';
|
|
81
|
+
return input
|
|
82
|
+
.trim()
|
|
83
|
+
// Remove directory traversal attempts
|
|
84
|
+
.replace(/\.\./g, '')
|
|
85
|
+
// Remove double slashes
|
|
86
|
+
.replace(/\/+/g, '/')
|
|
87
|
+
// Remove leading slashes (make relative)
|
|
88
|
+
.replace(/^\/+/, '')
|
|
89
|
+
// Remove shell special characters
|
|
90
|
+
.replace(/[;&|`$(){}[\]<>\\'"]/g, '');
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Convert string to camelCase
|
|
94
|
+
*/
|
|
95
|
+
function toCamelCase(input) {
|
|
96
|
+
if (!input)
|
|
97
|
+
return '';
|
|
98
|
+
const pascal = toPascalCase(input);
|
|
99
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Convert string to kebab-case
|
|
103
|
+
*/
|
|
104
|
+
function toKebabCase(input) {
|
|
105
|
+
if (!input)
|
|
106
|
+
return '';
|
|
107
|
+
return input
|
|
108
|
+
.trim()
|
|
109
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
110
|
+
.replace(/[\s_]+/g, '-')
|
|
111
|
+
.toLowerCase();
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Convert string to PascalCase
|
|
115
|
+
*/
|
|
116
|
+
function toPascalCase(input) {
|
|
117
|
+
if (!input)
|
|
118
|
+
return '';
|
|
119
|
+
return input
|
|
120
|
+
.trim()
|
|
121
|
+
.replace(/[-_\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''))
|
|
122
|
+
.replace(/^(.)/, (char) => char.toUpperCase());
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Validate a branch name
|
|
126
|
+
*/
|
|
127
|
+
function validateBranchName(input) {
|
|
128
|
+
return validatePattern(input, exports.ValidationRules.branchName, 'Invalid branch name. Use alphanumeric characters, dots, underscores, or hyphens.');
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Validate a module/class name (PascalCase)
|
|
132
|
+
*/
|
|
133
|
+
function validateClassName(input) {
|
|
134
|
+
return validatePattern(input, exports.ValidationRules.className, 'Invalid class name. Must start with uppercase letter and contain only alphanumeric characters.');
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Validate an email address
|
|
138
|
+
*/
|
|
139
|
+
function validateEmail(input) {
|
|
140
|
+
return validatePattern(input, exports.ValidationRules.email, 'Invalid email address format.');
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Validate a file/directory name
|
|
144
|
+
*/
|
|
145
|
+
function validateFileName(input) {
|
|
146
|
+
return validatePattern(input, exports.ValidationRules.fileName, 'Invalid file name. Use only alphanumeric characters, dots, underscores, or hyphens.');
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Validate a kebab-case name
|
|
150
|
+
*/
|
|
151
|
+
function validateKebabCase(input) {
|
|
152
|
+
return validatePattern(input, exports.ValidationRules.kebabCase, 'Invalid name. Must be lowercase with hyphens (kebab-case).');
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Validate input length
|
|
156
|
+
*/
|
|
157
|
+
function validateLength(input, min, max, fieldName = 'Input') {
|
|
158
|
+
if (!input || input.trim() === '') {
|
|
159
|
+
return { error: `${fieldName} is required`, valid: false };
|
|
160
|
+
}
|
|
161
|
+
const trimmed = input.trim();
|
|
162
|
+
if (trimmed.length < min) {
|
|
163
|
+
return { error: `${fieldName} must be at least ${min} characters`, valid: false };
|
|
164
|
+
}
|
|
165
|
+
if (trimmed.length > max) {
|
|
166
|
+
return { error: `${fieldName} must be at most ${max} characters`, valid: false };
|
|
167
|
+
}
|
|
168
|
+
return { valid: true, value: trimmed };
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Validate an npm package name
|
|
172
|
+
*/
|
|
173
|
+
function validateNpmPackage(input) {
|
|
174
|
+
return validatePattern(input, exports.ValidationRules.npmPackage, 'Invalid npm package name.');
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Validate input against a pattern
|
|
178
|
+
*/
|
|
179
|
+
function validatePattern(input, pattern, errorMessage) {
|
|
180
|
+
if (!input || input.trim() === '') {
|
|
181
|
+
return { error: 'Input is required', valid: false };
|
|
182
|
+
}
|
|
183
|
+
const trimmed = input.trim();
|
|
184
|
+
if (!pattern.test(trimmed)) {
|
|
185
|
+
return { error: errorMessage, valid: false };
|
|
186
|
+
}
|
|
187
|
+
return { valid: true, value: trimmed };
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Validate a property name (camelCase)
|
|
191
|
+
*/
|
|
192
|
+
function validatePropertyName(input) {
|
|
193
|
+
return validatePattern(input, exports.ValidationRules.propertyName, 'Invalid property name. Must start with lowercase letter (camelCase).');
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Validate required input with custom validator
|
|
197
|
+
*/
|
|
198
|
+
function validateRequired(value, fieldName) {
|
|
199
|
+
if (value === null || value === undefined || value === '') {
|
|
200
|
+
return { error: `${fieldName} is required`, valid: false };
|
|
201
|
+
}
|
|
202
|
+
return { valid: true, value: String(value) };
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvdmFsaWRhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztHQUdHOzs7QUF3REgsc0NBV0M7QUFLRCxvQ0FhQztBQUtELGtDQUtDO0FBS0Qsa0NBUUM7QUFLRCxvQ0FPQztBQUtELGdEQU1DO0FBS0QsOENBTUM7QUFLRCxzQ0FFQztBQUtELDRDQU1DO0FBS0QsOENBTUM7QUFLRCx3Q0FtQkM7QUFLRCxnREFNQztBQUtELDBDQWVDO0FBS0Qsb0RBTUM7QUFLRCw0Q0FRQztBQWxQRDs7R0FFRztBQUNVLFFBQUEsZUFBZSxHQUFHO0lBQzdCOztPQUVHO0lBQ0gsVUFBVSxFQUFFLHVEQUF1RDtJQUVuRTs7T0FFRztJQUNILFNBQVMsRUFBRSxxQkFBcUI7SUFFaEM7O09BRUc7SUFDSCxLQUFLLEVBQUUsNEJBQTRCO0lBRW5DOztPQUVHO0lBQ0gsUUFBUSxFQUFFLG1CQUFtQjtJQUU3Qjs7T0FFRztJQUNILFNBQVMsRUFBRSwrQkFBK0I7SUFFMUM7O09BRUc7SUFDSCxVQUFVLEVBQUUsd0RBQXdEO0lBRXBFOztPQUVHO0lBQ0gsWUFBWSxFQUFFLHFCQUFxQjtJQUVuQzs7T0FFRztJQUNILE1BQU0sRUFBRSxzREFBc0Q7Q0FDL0QsQ0FBQztBQUVGOztHQUVHO0FBQ0gsU0FBZ0IsYUFBYSxDQUFDLEtBQWE7SUFDekMsSUFBSSxDQUFDLEtBQUs7UUFBRSxPQUFPLEVBQUUsQ0FBQztJQUV0QixPQUFPLEtBQUs7U0FDVCxJQUFJLEVBQUU7UUFDUCxrQ0FBa0M7U0FDakMsT0FBTyxDQUFDLHVCQUF1QixFQUFFLEVBQUUsQ0FBQztRQUNyQyw0QkFBNEI7U0FDM0IsT0FBTyxDQUFDLGtCQUFrQixFQUFFLEVBQUUsQ0FBQztRQUNoQywyQkFBMkI7U0FDMUIsT0FBTyxDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsQ0FBQztBQUMxQixDQUFDO0FBRUQ7O0dBRUc7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
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# lt completion for Bash shell
|
|
2
|
+
# Auto-generated by lt CLI - supports arbitrary nesting depth
|
|
3
|
+
|
|
4
|
+
<%
|
|
5
|
+
// Helper to generate safe variable name from path
|
|
6
|
+
function varName(path) {
|
|
7
|
+
return path.replace(/-/g, '_') + '_cmds';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Recursively collect all nodes that have children
|
|
11
|
+
function collectNodesWithChildren(nodes, result = []) {
|
|
12
|
+
for (const node of nodes) {
|
|
13
|
+
if (node.children.length > 0) {
|
|
14
|
+
result.push(node);
|
|
15
|
+
collectNodesWithChildren(node.children, result);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Get command names from children
|
|
22
|
+
function getCommandNames(children) {
|
|
23
|
+
return children.map(c => c.name).join(' ');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const nodesWithChildren = collectNodesWithChildren(props.commandTree);
|
|
27
|
+
-%>
|
|
28
|
+
_lt_completions() {
|
|
29
|
+
local cur prev words cword
|
|
30
|
+
_init_completion || return
|
|
31
|
+
|
|
32
|
+
# Root level commands
|
|
33
|
+
local root_cmds="<%- getCommandNames(props.commandTree) %>"
|
|
34
|
+
|
|
35
|
+
<% for (const node of nodesWithChildren) { -%>
|
|
36
|
+
# <%- node.path %> subcommands
|
|
37
|
+
local <%- varName(node.path) %>="<%- getCommandNames(node.children) %>"
|
|
38
|
+
|
|
39
|
+
<% } -%>
|
|
40
|
+
case "${cword}" in
|
|
41
|
+
1)
|
|
42
|
+
COMPREPLY=( $(compgen -W "${root_cmds}" -- "${cur}") )
|
|
43
|
+
;;
|
|
44
|
+
<% for (let depth = 2; depth <= props.maxDepth; depth++) { -%>
|
|
45
|
+
<%- depth %>)
|
|
46
|
+
<%
|
|
47
|
+
// Generate nested case statements for this depth
|
|
48
|
+
function generateBashCases(nodes, currentDepth, targetDepth, wordIndex) {
|
|
49
|
+
let output = '';
|
|
50
|
+
const indent = ' ' + ' '.repeat(currentDepth - 2);
|
|
51
|
+
|
|
52
|
+
if (currentDepth === targetDepth) {
|
|
53
|
+
// We're at the target depth, provide completions
|
|
54
|
+
for (const node of nodes) {
|
|
55
|
+
if (node.children.length > 0) {
|
|
56
|
+
output += `${indent}${node.name})\n`;
|
|
57
|
+
output += `${indent} COMPREPLY=( $(compgen -W "\${${varName(node.path)}}" -- "\${cur}") )\n`;
|
|
58
|
+
output += `${indent} ;;\n`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
// Need to go deeper with nested case
|
|
63
|
+
for (const node of nodes) {
|
|
64
|
+
if (node.children.length > 0) {
|
|
65
|
+
const hasGrandchildren = node.children.some(c => c.children.length > 0);
|
|
66
|
+
if (hasGrandchildren || currentDepth + 1 === targetDepth) {
|
|
67
|
+
output += `${indent}${node.name})\n`;
|
|
68
|
+
output += `${indent} case "\${words[${currentDepth}]}" in\n`;
|
|
69
|
+
output += generateBashCases(node.children, currentDepth + 1, targetDepth, wordIndex);
|
|
70
|
+
output += `${indent} esac\n`;
|
|
71
|
+
output += `${indent} ;;\n`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return output;
|
|
77
|
+
}
|
|
78
|
+
-%>
|
|
79
|
+
case "${words[1]}" in
|
|
80
|
+
<%- generateBashCases(props.commandTree, 2, depth, 1) -%>
|
|
81
|
+
esac
|
|
82
|
+
;;
|
|
83
|
+
<% } -%>
|
|
84
|
+
*)
|
|
85
|
+
# Complete common flags
|
|
86
|
+
local flags="--help --version --noConfirm --dry-run"
|
|
87
|
+
COMPREPLY=( $(compgen -W "${flags}" -- "${cur}") )
|
|
88
|
+
;;
|
|
89
|
+
esac
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
complete -F _lt_completions lt
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# lt completion for Fish shell
|
|
2
|
+
# Auto-generated by lt CLI - supports arbitrary nesting depth
|
|
3
|
+
|
|
4
|
+
<%
|
|
5
|
+
// Recursively collect all nodes for completion generation
|
|
6
|
+
function collectAllNodes(nodes, result = [], parentPath = []) {
|
|
7
|
+
for (const node of nodes) {
|
|
8
|
+
result.push({ node, parentPath: [...parentPath] });
|
|
9
|
+
if (node.children.length > 0) {
|
|
10
|
+
collectAllNodes(node.children, result, [...parentPath, node.name]);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Escape single quotes in description for Fish
|
|
17
|
+
function escapeDesc(desc) {
|
|
18
|
+
return desc.replace(/'/g, "\\'");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const allNodes = collectAllNodes(props.commandTree);
|
|
22
|
+
const rootCommands = props.commandTree.map(n => n.name).join(' ');
|
|
23
|
+
-%>
|
|
24
|
+
# Helper function to check command depth
|
|
25
|
+
function __lt_using_command
|
|
26
|
+
set -l cmd (commandline -opc)
|
|
27
|
+
set -l cmd_count (count $cmd)
|
|
28
|
+
|
|
29
|
+
if test $cmd_count -eq 1
|
|
30
|
+
return 0
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
for arg in $argv
|
|
34
|
+
if contains -- $arg $cmd
|
|
35
|
+
return 0
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
return 1
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Helper to check exact command path
|
|
42
|
+
function __lt_at_path
|
|
43
|
+
set -l cmd (commandline -opc)
|
|
44
|
+
set -l expected_len (math (count $argv) + 1)
|
|
45
|
+
|
|
46
|
+
if test (count $cmd) -ne $expected_len
|
|
47
|
+
return 1
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
set -l i 2
|
|
51
|
+
for expected in $argv
|
|
52
|
+
if test "$cmd[$i]" != "$expected"
|
|
53
|
+
return 1
|
|
54
|
+
end
|
|
55
|
+
set i (math $i + 1)
|
|
56
|
+
end
|
|
57
|
+
return 0
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Root level commands
|
|
61
|
+
set -l root_cmds <%- rootCommands %>
|
|
62
|
+
|
|
63
|
+
<% for (const { node, parentPath } of allNodes) { -%>
|
|
64
|
+
<% if (parentPath.length === 0) { -%>
|
|
65
|
+
# <%- node.name %> command
|
|
66
|
+
complete -f -c lt -n "not __fish_seen_subcommand_from $root_cmds" -a "<%- node.name %>" -d '<%- escapeDesc(node.description) %>'
|
|
67
|
+
<% } else { -%>
|
|
68
|
+
# <%- [...parentPath, node.name].join(' ') %> command
|
|
69
|
+
complete -f -c lt -n "__lt_at_path <%- parentPath.join(' ') %>" -a "<%- node.name %>" -d '<%- escapeDesc(node.description) %>'
|
|
70
|
+
<% } -%>
|
|
71
|
+
|
|
72
|
+
<% } -%>
|
|
73
|
+
# Common flags (available at any depth)
|
|
74
|
+
complete -f -c lt -l help -d 'Show help'
|
|
75
|
+
complete -f -c lt -l version -d 'Show version'
|
|
76
|
+
complete -f -c lt -l noConfirm -d 'Skip confirmations'
|
|
77
|
+
complete -f -c lt -l dry-run -d 'Show what would be done'
|