@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.
Files changed (73) hide show
  1. package/README.md +30 -0
  2. package/bin/postinstall.js +156 -0
  3. package/build/cli.js +11 -1
  4. package/build/commands/blocks/add.js +28 -306
  5. package/build/commands/blocks/blocks.js +2 -2
  6. package/build/commands/claude/claude.js +2 -2
  7. package/build/commands/cli/cli.js +2 -2
  8. package/build/commands/cli/create.js +69 -21
  9. package/build/commands/cli/rename.js +11 -5
  10. package/build/commands/completion.js +311 -0
  11. package/build/commands/components/add.js +25 -219
  12. package/build/commands/components/components.js +2 -2
  13. package/build/commands/config/help.js +5 -2
  14. package/build/commands/config/init.js +20 -5
  15. package/build/commands/config/show.js +4 -1
  16. package/build/commands/config/validate.js +27 -2
  17. package/build/commands/deployment/create.js +18 -5
  18. package/build/commands/deployment/deployment.js +2 -2
  19. package/build/commands/docs/open.js +4 -1
  20. package/build/commands/doctor.js +285 -0
  21. package/build/commands/frontend/angular.js +88 -28
  22. package/build/commands/frontend/nuxt.js +2 -1
  23. package/build/commands/fullstack/init.js +58 -19
  24. package/build/commands/git/clean.js +60 -11
  25. package/build/commands/git/clear.js +17 -11
  26. package/build/commands/git/create.js +51 -10
  27. package/build/commands/git/force-pull.js +42 -15
  28. package/build/commands/git/get.js +14 -15
  29. package/build/commands/git/install-scripts.js +6 -6
  30. package/build/commands/git/rebase.js +40 -12
  31. package/build/commands/git/rename.js +33 -13
  32. package/build/commands/git/reset.js +48 -13
  33. package/build/commands/git/squash.js +67 -26
  34. package/build/commands/git/undo.js +33 -13
  35. package/build/commands/git/update.js +59 -6
  36. package/build/commands/history.js +75 -0
  37. package/build/commands/mongodb/collection-export.js +2 -2
  38. package/build/commands/mongodb/mongodb.js +2 -2
  39. package/build/commands/mongodb/s3-restore.js +2 -2
  40. package/build/commands/npm/reinit.js +11 -12
  41. package/build/commands/npm/update.js +6 -2
  42. package/build/commands/qdrant/delete.js +6 -2
  43. package/build/commands/qdrant/qdrant.js +2 -2
  44. package/build/commands/qdrant/stats.js +5 -2
  45. package/build/commands/redis/redis.js +2 -2
  46. package/build/commands/server/add-property.js +8 -12
  47. package/build/commands/server/create-secret.js +6 -3
  48. package/build/commands/server/create.js +39 -21
  49. package/build/commands/server/module.js +22 -16
  50. package/build/commands/server/object.js +7 -11
  51. package/build/commands/server/set-secrets.js +6 -3
  52. package/build/commands/server/test.js +3 -3
  53. package/build/commands/starter/chrome-extension.js +3 -3
  54. package/build/commands/status.js +198 -0
  55. package/build/commands/templates/list.js +107 -0
  56. package/build/commands/templates/llm.js +8 -3
  57. package/build/commands/templates/templates.js +2 -2
  58. package/build/commands/tools/jwt-read.js +2 -2
  59. package/build/commands/tools/regex.js +5 -2
  60. package/build/commands/typescript/create.js +84 -21
  61. package/build/commands/typescript/playground.js +5 -2
  62. package/build/extensions/config.js +37 -1
  63. package/build/extensions/git.js +57 -2
  64. package/build/extensions/history.js +118 -0
  65. package/build/extensions/logger.js +189 -0
  66. package/build/lib/nuxt-base-components.js +249 -0
  67. package/build/lib/validation.js +204 -0
  68. package/build/templates/completion/bash.sh.ejs +92 -0
  69. package/build/templates/completion/fish.sh.ejs +77 -0
  70. package/build/templates/completion/zsh.sh.ejs +119 -0
  71. package/docs/commands.md +464 -14
  72. package/docs/lt.config.md +138 -8
  73. 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnV4dC1iYXNlLWNvbXBvbmVudHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbGliL251eHQtYmFzZS1jb21wb25lbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBdUJBLHdDQThDQztBQUtELDRCQXlFQztBQUtELDhCQVNDO0FBS0QsNENBY0M7QUFLRCxrQ0FlQztBQUtELHdDQThCQztBQUtELHNDQW1DQztBQW5SRDs7O0dBR0c7QUFDSCxpQ0FBMEI7QUFDMUIseUJBQXlCO0FBQ3pCLDZCQUE2QjtBQUM3QixxQ0FBcUM7QUFDckMsNkJBQTZCO0FBSTdCLE1BQU0sZUFBZSxHQUFHLHVFQUF1RSxDQUFDO0FBQ2hHLE1BQU0sY0FBYyxHQUFHLHNFQUFzRSxDQUFDO0FBTzlGOztHQUVHO0FBQ0gsU0FBc0IsY0FBYzt5REFDbEMsVUFBa0IsRUFDbEIsT0FBK0IsRUFDL0IsU0FBUyxHQUFHLEtBQUs7UUFFakIsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUM7UUFDbEMsTUFBTSxNQUFNLEdBQUcsR0FBRyxlQUFlLGdCQUFnQixVQUFVLEtBQUssQ0FBQztRQUNqRSxNQUFNLFFBQVEsR0FBRyxNQUFNLGVBQUssQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFekMsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQzVCLE1BQU0sVUFBVSxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUM7WUFDakMsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQzFCLElBQUksZUFBdUIsQ0FBQztZQUU1QixJQUFJLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsYUFBYSxDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUNwRCxlQUFlLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsYUFBYSxDQUFDLENBQUM7WUFDckQsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztnQkFFeEQsSUFBSSxXQUFXLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUMzQixlQUFlLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ25ELENBQUM7cUJBQU0sQ0FBQztvQkFDTixlQUFlLEdBQUcsR0FBRyxDQUFDO2dCQUN4QixDQUFDO1lBQ0gsQ0FBQztZQUVELHFDQUFxQztZQUNyQyxJQUFJLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsR0FBRyxVQUFVLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDbEUsS0FBSyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsVUFBVSxpQkFBaUIsQ0FBQyxDQUFDO2dCQUMxRCxPQUFPO1lBQ1QsQ0FBQztZQUVELElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDZixNQUFNLFVBQVUsR0FBRyxNQUFNLE1BQU0sQ0FBQyxPQUFPLENBQUMsa0JBQWtCLFVBQVUseUNBQXlDLENBQUMsQ0FBQztnQkFDL0csSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO29CQUNoQixPQUFPO2dCQUNULENBQUM7WUFDSCxDQUFDO1lBRUQsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsR0FBRyxVQUFVLEtBQUssQ0FBQyxDQUFDO1lBQ2xFLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsdUJBQXVCLFVBQVUsT0FBTyxVQUFVLEtBQUssQ0FBQyxDQUFDO1lBQ3BGLEVBQUUsQ0FBQyxhQUFhLENBQUMsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBQ3pDLE9BQU8sQ0FBQyxPQUFPLENBQUMsa0JBQWtCLFVBQVUsK0JBQStCLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDM0YsQ0FBQzthQUFNLENBQUM7WUFDTixLQUFLLENBQUMsS0FBSyxDQUFDLDBDQUEwQyxRQUFRLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUMvRSxDQUFDO0lBQ0gsQ0FBQztDQUFBO0FBRUQ7O0dBRUc7QUFDSCxTQUFzQixRQUFRO3lEQUM1QixJQUFjLEVBQ2QsT0FBK0IsRUFDL0IsSUFBNkIsRUFDN0IsU0FBUyxHQUFHLEtBQUs7UUFFakIsTUFBTSxFQUFFLEtBQUssRUFBRSxHQUFHLE9BQU8sQ0FBQztRQUMxQixNQUFNLE1BQU0sR0FBRyxHQUFHLGVBQWUsSUFBSSxJQUFJLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3pELE1BQU0sYUFBYSxHQUFHLElBQUksS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDO1FBRWpFLE1BQU0sTUFBTSxHQUFHLE1BQU0sZ0JBQWdCLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxPQUFPLEVBQUUsSUFBSSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUVyRyxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ1gsTUFBTSxhQUFhLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFDeEQsQ0FBQztRQUVELE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxJQUFJLGlCQUFpQixDQUFDLENBQUM7UUFDeEYsTUFBTSxRQUFRLEdBQUcsTUFBTSxlQUFLLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3pDLFdBQVcsQ0FBQyxPQUFPLENBQUMsR0FBRyxJQUFJLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFdBQVcsSUFBSSxJQUFJLENBQUMsSUFBSSxrQ0FBa0MsQ0FBQyxDQUFDO1FBRWpILElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQztZQUM1QixNQUFNLFVBQVUsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDO1lBQ2pDLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUMxQixJQUFJLGVBQXVCLENBQUM7WUFFNUIsSUFBSSxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLGFBQWEsQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDcEQsZUFBZSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLGFBQWEsQ0FBQyxDQUFDO1lBQ3JELENBQUM7aUJBQU0sQ0FBQztnQkFDTixNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssYUFBYSxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO2dCQUU3RCxJQUFJLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQzNCLGVBQWUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDbkQsQ0FBQztxQkFBTSxDQUFDO29CQUNOLGVBQWUsR0FBRyxHQUFHLENBQUM7Z0JBQ3hCLENBQUM7WUFDSCxDQUFDO1lBRUQsSUFBSSxVQUFVLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztZQUMzQixJQUFJLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDdEIsVUFBVSxHQUFHLElBQUksQ0FBQyxJQUFJO3FCQUNuQixPQUFPLENBQUMsaUJBQWlCLEVBQUUsT0FBTyxDQUFDO3FCQUNuQyxXQUFXLEVBQUU7cUJBQ2IsT0FBTyxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUM1QixDQUFDO1lBQ0QsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFFMUQsK0JBQStCO1lBQy9CLElBQUksRUFBRSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO2dCQUM5QixLQUFLLENBQUMsSUFBSSxDQUFDLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxpQkFBaUIsQ0FBQyxDQUFDO2dCQUNuRSxPQUFPLFVBQVUsQ0FBQztZQUNwQixDQUFDO1lBRUQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztnQkFDcEMsTUFBTSxnQkFBZ0IsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLGtDQUFrQyxDQUFDLENBQUM7Z0JBQ3hFLEVBQUUsQ0FBQyxTQUFTLENBQUMsZUFBZSxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7Z0JBQ25ELGdCQUFnQixDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQzdCLENBQUM7WUFFRCxJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDM0QsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ3hDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFLE9BQU8sQ0FBQyxDQUFDO2dCQUNwRCxJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO29CQUM1QixFQUFFLENBQUMsU0FBUyxDQUFDLE9BQU8sRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO2dCQUM3QyxDQUFDO1lBQ0gsQ0FBQztZQUVELE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsWUFBWSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLFVBQVUsT0FBTyxVQUFVLEtBQUssQ0FBQyxDQUFDO1lBQzlGLEVBQUUsQ0FBQyxhQUFhLENBQUMsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBQ3pDLE9BQU8sQ0FBQyxPQUFPLENBQUMsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLFVBQVUsK0JBQStCLFVBQVUsRUFBRSxDQUFDLENBQUM7WUFDbkcsT0FBTyxVQUFVLENBQUM7UUFDcEIsQ0FBQzthQUFNLENBQUM7WUFDTixNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxRQUFRLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUNuRixDQUFDO0lBQ0gsQ0FBQztDQUFBO0FBRUQ7O0dBRUc7QUFDSCxTQUFzQixTQUFTOztRQUM3QixNQUFNLFlBQVksR0FBRyxHQUFHLGVBQWUsY0FBYyxDQUFDO1FBQ3RELE1BQU0sUUFBUSxHQUFHLE1BQU0sZUFBSyxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUUvQyxJQUFJLFFBQVEsQ0FBQyxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUM7WUFDNUIsT0FBTyxRQUFRLENBQUMsSUFBSSxDQUFDO1FBQ3ZCLENBQUM7YUFBTSxDQUFDO1lBQ04sTUFBTSxJQUFJLEtBQUssQ0FBQyx3REFBd0QsUUFBUSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDakcsQ0FBQztJQUNILENBQUM7Q0FBQTtBQUVEOztHQUVHO0FBQ0gsU0FBc0IsZ0JBQWdCLENBQ3BDLFFBQWdCLEVBQ2hCLE9BQStCLEVBQy9CLElBQTJCOztRQUUzQixNQUFNLEVBQUUsS0FBSyxFQUFFLEdBQUcsT0FBTyxDQUFDO1FBQzFCLE1BQU0sYUFBYSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsMkJBQTJCLElBQUksS0FBSyxDQUFDLENBQUM7UUFFdkUsTUFBTSxJQUFJLEdBQUcsTUFBTSxTQUFTLEVBQUUsQ0FBQztRQUMvQixNQUFNLElBQUksR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDeEQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUVwQyxhQUFhLENBQUMsT0FBTyxDQUFDLGNBQWMsUUFBUSxzQkFBc0IsQ0FBQyxDQUFDO1FBQ3BFLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDckMsQ0FBQztDQUFBO0FBRUQ7O0dBRUc7QUFDSCxTQUFzQixXQUFXLENBQy9CLElBQTZCLEVBQzdCLE9BQWdCOztRQUVoQixNQUFNLFlBQVksR0FBRyxHQUFHLGNBQWMsSUFBSSxJQUFJLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUNoRixNQUFNLFFBQVEsR0FBRyxNQUFNLGVBQUssQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUM7UUFFL0MsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQzVCLE9BQU8sUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFTLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQ3ZDLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSTtnQkFDZixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUk7YUFDaEIsQ0FBQyxDQUFDLENBQUM7UUFDTixDQUFDO2FBQU0sQ0FBQztZQUNOLE1BQU0sSUFBSSxLQUFLLENBQUMsb0RBQW9ELFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO1FBQzdGLENBQUM7SUFDSCxDQUFDO0NBQUE7QUFFRDs7R0FFRztBQUNILFNBQXNCLGNBQWM7eURBQ2xDLFdBQW1CLEVBQ25CLE9BQStCLEVBQy9CLFNBQVMsR0FBRyxLQUFLO1FBRWpCLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQztRQUUxQyxNQUFNLGtCQUFrQixHQUFHLFdBQVcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksV0FBVyxDQUFDO1FBQ3BFLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLGNBQWMsQ0FBQyxDQUFDO1FBQ3BFLE1BQU0sV0FBVyxHQUFHLG9CQUFVLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUM3RCxNQUFNLFdBQVcsR0FDYixDQUFDLFdBQVcsQ0FBQyxZQUFZLElBQUksV0FBVyxDQUFDLFlBQVksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO2VBQ3pFLENBQUMsV0FBVyxDQUFDLGVBQWUsSUFBSSxXQUFXLENBQUMsZUFBZSxDQUFDLGtCQUFrQixDQUFDLENBQUMsQ0FBQztRQUV0RixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDakIsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUNmLE1BQU0sY0FBYyxHQUFHLE1BQU0sTUFBTSxDQUFDLE9BQU8sQ0FDekMsbUJBQW1CLGtCQUFrQiw2Q0FBNkMsQ0FDbkYsQ0FBQztnQkFDRixJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7b0JBQ3BCLE9BQU87Z0JBQ1QsQ0FBQztZQUNILENBQUM7WUFFRCxNQUFNLGNBQWMsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLHVCQUF1QixrQkFBa0IsS0FBSyxDQUFDLENBQUM7WUFDbEYsTUFBTSxNQUFNLENBQUMsR0FBRyxDQUFDLGVBQWUsV0FBVyxlQUFlLENBQUMsQ0FBQztZQUM1RCxjQUFjLENBQUMsT0FBTyxDQUFDLGVBQWUsa0JBQWtCLHlCQUF5QixDQUFDLENBQUM7UUFDckYsQ0FBQzthQUFNLENBQUM7WUFDTixLQUFLLENBQUMsSUFBSSxDQUFDLGVBQWUsa0JBQWtCLHVCQUF1QixDQUFDLENBQUM7UUFDdkUsQ0FBQztJQUNILENBQUM7Q0FBQTtBQUVEOztHQUVHO0FBQ0gsU0FBc0IsYUFBYTt5REFDakMsTUFBVyxFQUNYLE9BQStCLEVBQy9CLElBQTZCLEVBQzdCLFNBQVMsR0FBRyxLQUFLO1FBRWpCLElBQUksTUFBTSxhQUFOLE1BQU0sdUJBQU4sTUFBTSxDQUFFLEdBQUcsRUFBRSxDQUFDO1lBQ2hCLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUM7WUFDL0IsS0FBSyxNQUFNLFVBQVUsSUFBSSxXQUFXLEVBQUUsQ0FBQztnQkFDckMsTUFBTSxjQUFjLENBQUMsVUFBVSxFQUFFLE9BQU8sRUFBRSxTQUFTLENBQUMsQ0FBQztZQUN2RCxDQUFDO1FBQ0gsQ0FBQztRQUVELElBQUksTUFBTSxhQUFOLE1BQU0sdUJBQU4sTUFBTSxDQUFFLFdBQVcsRUFBRSxDQUFDO1lBQ3hCLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUM7WUFDdkMsS0FBSyxNQUFNLFVBQVUsSUFBSSxXQUFXLEVBQUUsQ0FBQztnQkFDckMsTUFBTSxjQUFjLENBQUMsVUFBVSxFQUFFLE9BQU8sRUFBRSxTQUFTLENBQUMsQ0FBQztZQUN2RCxDQUFDO1FBQ0gsQ0FBQztRQUVELElBQUksTUFBTSxhQUFOLE1BQU0sdUJBQU4sTUFBTSxDQUFFLFVBQVUsRUFBRSxDQUFDO1lBQ3ZCLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUM7WUFDckMsS0FBSyxNQUFNLFNBQVMsSUFBSSxVQUFVLEVBQUUsQ0FBQztnQkFDbkMsSUFBSSxTQUFTLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7b0JBQzdCLE1BQU0sVUFBVSxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7b0JBQzNDLE1BQU0sY0FBYyxHQUFHLE1BQU0sV0FBVyxDQUFDLFlBQVksRUFBRSxVQUFVLENBQUMsQ0FBQztvQkFFbkUsS0FBSyxNQUFNLElBQUksSUFBSSxjQUFjLEVBQUUsQ0FBQzt3QkFDbEMsTUFBTSxRQUFRLENBQUMsRUFBRSxJQUFJLEVBQUUsR0FBRyxVQUFVLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLFNBQVMsQ0FBQyxDQUFDO29CQUN4RyxDQUFDO2dCQUNILENBQUM7cUJBQU0sQ0FBQztvQkFDTixNQUFNLFFBQVEsQ0FBQyxFQUFFLElBQUksRUFBRSxHQUFHLFNBQVMsTUFBTSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLFNBQVMsQ0FBQyxDQUFDO2dCQUMvRixDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0NBQUEifQ==
@@ -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'