lsh-framework 1.2.0 → 1.2.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 +40 -3
- package/dist/cli.js +104 -486
- package/dist/commands/doctor.js +427 -0
- package/dist/commands/init.js +371 -0
- package/dist/constants/api.js +94 -0
- package/dist/constants/commands.js +64 -0
- package/dist/constants/config.js +56 -0
- package/dist/constants/database.js +21 -0
- package/dist/constants/errors.js +79 -0
- package/dist/constants/index.js +28 -0
- package/dist/constants/paths.js +28 -0
- package/dist/constants/ui.js +73 -0
- package/dist/constants/validation.js +124 -0
- package/dist/daemon/lshd.js +11 -32
- package/dist/lib/daemon-client-helper.js +7 -4
- package/dist/lib/daemon-client.js +9 -2
- package/dist/lib/format-utils.js +163 -0
- package/dist/lib/job-manager.js +2 -1
- package/dist/lib/platform-utils.js +211 -0
- package/dist/lib/secrets-manager.js +11 -1
- package/dist/lib/string-utils.js +128 -0
- package/dist/services/daemon/daemon-registrar.js +3 -2
- package/dist/services/secrets/secrets.js +54 -30
- package/package.json +10 -74
- package/dist/app.js +0 -33
- package/dist/cicd/analytics.js +0 -261
- package/dist/cicd/auth.js +0 -269
- package/dist/cicd/cache-manager.js +0 -172
- package/dist/cicd/data-retention.js +0 -305
- package/dist/cicd/performance-monitor.js +0 -224
- package/dist/cicd/webhook-receiver.js +0 -640
- package/dist/commands/api.js +0 -346
- package/dist/commands/theme.js +0 -261
- package/dist/commands/zsh-import.js +0 -240
- package/dist/components/App.js +0 -1
- package/dist/components/Divider.js +0 -29
- package/dist/components/REPL.js +0 -43
- package/dist/components/Terminal.js +0 -232
- package/dist/components/UserInput.js +0 -30
- package/dist/daemon/api-server.js +0 -316
- package/dist/daemon/monitoring-api.js +0 -220
- package/dist/lib/api-error-handler.js +0 -185
- package/dist/lib/associative-arrays.js +0 -285
- package/dist/lib/base-api-server.js +0 -290
- package/dist/lib/brace-expansion.js +0 -160
- package/dist/lib/builtin-commands.js +0 -439
- package/dist/lib/executors/builtin-executor.js +0 -52
- package/dist/lib/extended-globbing.js +0 -411
- package/dist/lib/extended-parameter-expansion.js +0 -227
- package/dist/lib/interactive-shell.js +0 -460
- package/dist/lib/job-builtins.js +0 -582
- package/dist/lib/pathname-expansion.js +0 -216
- package/dist/lib/script-runner.js +0 -226
- package/dist/lib/shell-executor.js +0 -2504
- package/dist/lib/shell-parser.js +0 -958
- package/dist/lib/shell-types.js +0 -6
- package/dist/lib/shell.lib.js +0 -40
- package/dist/lib/theme-manager.js +0 -476
- package/dist/lib/variable-expansion.js +0 -385
- package/dist/lib/zsh-compatibility.js +0 -659
- package/dist/lib/zsh-import-manager.js +0 -707
- package/dist/lib/zsh-options.js +0 -328
- package/dist/pipeline/job-tracker.js +0 -491
- package/dist/pipeline/mcli-bridge.js +0 -309
- package/dist/pipeline/pipeline-service.js +0 -1119
- package/dist/pipeline/workflow-engine.js +0 -870
- package/dist/services/api/api.js +0 -58
- package/dist/services/api/auth.js +0 -35
- package/dist/services/api/config.js +0 -7
- package/dist/services/api/file.js +0 -22
- package/dist/services/shell/shell.js +0 -28
- package/dist/services/zapier.js +0 -16
- package/dist/simple-api-server.js +0 -148
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base API Server
|
|
3
|
-
* Abstract base class for all API servers to eliminate duplication in:
|
|
4
|
-
* - Express middleware setup
|
|
5
|
-
* - Server lifecycle management
|
|
6
|
-
* - Signal handling
|
|
7
|
-
* - Error handling
|
|
8
|
-
*/
|
|
9
|
-
import express from 'express';
|
|
10
|
-
import cors from 'cors';
|
|
11
|
-
import helmet from 'helmet';
|
|
12
|
-
import { EventEmitter } from 'events';
|
|
13
|
-
import { createLogger } from './logger.js';
|
|
14
|
-
/**
|
|
15
|
-
* Abstract base class for API servers
|
|
16
|
-
*
|
|
17
|
-
* Provides:
|
|
18
|
-
* - Express app setup with common middleware
|
|
19
|
-
* - Server lifecycle (start/stop)
|
|
20
|
-
* - Signal handling (SIGTERM, SIGINT, SIGHUP)
|
|
21
|
-
* - Error handling (uncaughtException, unhandledRejection)
|
|
22
|
-
* - Request logging
|
|
23
|
-
* - Structured logging
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```typescript
|
|
27
|
-
* class MyAPIServer extends BaseAPIServer {
|
|
28
|
-
* constructor() {
|
|
29
|
-
* super({ port: 3000 }, 'MyAPI');
|
|
30
|
-
* }
|
|
31
|
-
*
|
|
32
|
-
* protected setupRoutes(): void {
|
|
33
|
-
* this.app.get('/api/hello', (req, res) => {
|
|
34
|
-
* res.json({ message: 'Hello World' });
|
|
35
|
-
* });
|
|
36
|
-
* }
|
|
37
|
-
* }
|
|
38
|
-
* ```
|
|
39
|
-
*/
|
|
40
|
-
export class BaseAPIServer extends EventEmitter {
|
|
41
|
-
app;
|
|
42
|
-
server;
|
|
43
|
-
config;
|
|
44
|
-
logger;
|
|
45
|
-
isShuttingDown = false;
|
|
46
|
-
/**
|
|
47
|
-
* Create a new API server
|
|
48
|
-
*
|
|
49
|
-
* @param config - Server configuration
|
|
50
|
-
* @param loggerName - Name for the logger context
|
|
51
|
-
*/
|
|
52
|
-
constructor(config, loggerName) {
|
|
53
|
-
super();
|
|
54
|
-
this.config = {
|
|
55
|
-
port: 3000,
|
|
56
|
-
corsOrigins: '*',
|
|
57
|
-
enableHelmet: true,
|
|
58
|
-
jsonLimit: '10mb',
|
|
59
|
-
enableRequestLogging: true,
|
|
60
|
-
enableSignalHandlers: true,
|
|
61
|
-
enableErrorHandlers: true,
|
|
62
|
-
...config
|
|
63
|
-
};
|
|
64
|
-
this.logger = createLogger(loggerName);
|
|
65
|
-
this.app = express();
|
|
66
|
-
this.setupMiddleware();
|
|
67
|
-
if (this.config.enableErrorHandlers) {
|
|
68
|
-
this.setupErrorHandlers();
|
|
69
|
-
}
|
|
70
|
-
if (this.config.enableSignalHandlers) {
|
|
71
|
-
this.setupSignalHandlers();
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Setup Express middleware
|
|
76
|
-
* Can be overridden for custom middleware setup
|
|
77
|
-
*/
|
|
78
|
-
setupMiddleware() {
|
|
79
|
-
// Security middleware
|
|
80
|
-
if (this.config.enableHelmet) {
|
|
81
|
-
this.app.use(helmet({
|
|
82
|
-
crossOriginEmbedderPolicy: false,
|
|
83
|
-
}));
|
|
84
|
-
}
|
|
85
|
-
// CORS
|
|
86
|
-
this.app.use(this.configureCORS());
|
|
87
|
-
// Body parsing
|
|
88
|
-
this.app.use(express.json({ limit: this.config.jsonLimit }));
|
|
89
|
-
this.app.use(express.urlencoded({ extended: true }));
|
|
90
|
-
// Request logging
|
|
91
|
-
if (this.config.enableRequestLogging) {
|
|
92
|
-
this.app.use(this.requestLogger.bind(this));
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Configure CORS middleware
|
|
97
|
-
* Can be overridden for custom CORS configuration
|
|
98
|
-
*/
|
|
99
|
-
configureCORS() {
|
|
100
|
-
const origins = this.config.corsOrigins;
|
|
101
|
-
if (origins === '*') {
|
|
102
|
-
return cors();
|
|
103
|
-
}
|
|
104
|
-
if (Array.isArray(origins)) {
|
|
105
|
-
return cors({
|
|
106
|
-
origin: (origin, callback) => {
|
|
107
|
-
if (!origin || origins.some(pattern => {
|
|
108
|
-
const regex = new RegExp(pattern.replace(/\*/g, '.*'));
|
|
109
|
-
return regex.test(origin);
|
|
110
|
-
})) {
|
|
111
|
-
callback(null, true);
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
callback(new Error('Not allowed by CORS'));
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
return cors({ origin: origins });
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Request logging middleware
|
|
123
|
-
*/
|
|
124
|
-
requestLogger(req, res, next) {
|
|
125
|
-
this.logger.info(`${req.method} ${req.path}`);
|
|
126
|
-
next();
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Setup error handlers for uncaught exceptions and unhandled rejections
|
|
130
|
-
*/
|
|
131
|
-
setupErrorHandlers() {
|
|
132
|
-
process.on('uncaughtException', (error) => {
|
|
133
|
-
this.logger.error('Uncaught Exception', error);
|
|
134
|
-
this.handleFatalError(error);
|
|
135
|
-
});
|
|
136
|
-
process.on('unhandledRejection', (reason, promise) => {
|
|
137
|
-
this.logger.error('Unhandled Rejection', reason instanceof Error ? reason : new Error(String(reason)), {
|
|
138
|
-
promise: String(promise)
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Setup signal handlers for graceful shutdown
|
|
144
|
-
*/
|
|
145
|
-
setupSignalHandlers() {
|
|
146
|
-
const signals = ['SIGTERM', 'SIGINT'];
|
|
147
|
-
signals.forEach(signal => {
|
|
148
|
-
process.on(signal, () => {
|
|
149
|
-
this.logger.info(`Received ${signal}, initiating graceful shutdown`);
|
|
150
|
-
this.gracefulShutdown(signal);
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
process.on('SIGHUP', () => {
|
|
154
|
-
this.logger.info('Received SIGHUP');
|
|
155
|
-
this.handleSIGHUP();
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Handle SIGHUP signal - can be overridden for custom behavior (e.g., reload config)
|
|
160
|
-
*/
|
|
161
|
-
handleSIGHUP() {
|
|
162
|
-
this.logger.info('SIGHUP handler not implemented, ignoring');
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Handle fatal errors
|
|
166
|
-
* @param error - The fatal error
|
|
167
|
-
*/
|
|
168
|
-
handleFatalError(error) {
|
|
169
|
-
this.logger.error('Fatal error, shutting down', error);
|
|
170
|
-
process.exit(1);
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Perform graceful shutdown
|
|
174
|
-
* @param signal - The signal that triggered the shutdown
|
|
175
|
-
*/
|
|
176
|
-
async gracefulShutdown(signal) {
|
|
177
|
-
if (this.isShuttingDown) {
|
|
178
|
-
this.logger.warn('Shutdown already in progress');
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
this.isShuttingDown = true;
|
|
182
|
-
this.logger.info(`Graceful shutdown initiated by ${signal}`);
|
|
183
|
-
try {
|
|
184
|
-
// Give ongoing requests time to complete
|
|
185
|
-
await this.stop();
|
|
186
|
-
this.logger.info('Server stopped successfully');
|
|
187
|
-
process.exit(0);
|
|
188
|
-
}
|
|
189
|
-
catch (error) {
|
|
190
|
-
this.logger.error('Error during shutdown', error);
|
|
191
|
-
process.exit(1);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Start the API server
|
|
196
|
-
* @returns Promise that resolves when server is listening
|
|
197
|
-
*/
|
|
198
|
-
async start() {
|
|
199
|
-
return new Promise((resolve, reject) => {
|
|
200
|
-
try {
|
|
201
|
-
// Setup routes before starting server
|
|
202
|
-
this.setupRoutes();
|
|
203
|
-
this.server = this.app.listen(this.config.port, () => {
|
|
204
|
-
this.logger.info(`Server started on port ${this.config.port}`);
|
|
205
|
-
this.emit('started');
|
|
206
|
-
resolve();
|
|
207
|
-
});
|
|
208
|
-
this.server.on('error', (error) => {
|
|
209
|
-
this.logger.error('Server error', error);
|
|
210
|
-
this.emit('error', error);
|
|
211
|
-
reject(error);
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
catch (error) {
|
|
215
|
-
this.logger.error('Failed to start server', error);
|
|
216
|
-
reject(error);
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Stop the API server
|
|
222
|
-
* @param timeout - Maximum time to wait for connections to close (ms)
|
|
223
|
-
* @returns Promise that resolves when server is stopped
|
|
224
|
-
*/
|
|
225
|
-
async stop(timeout = 5000) {
|
|
226
|
-
return new Promise((resolve, reject) => {
|
|
227
|
-
if (!this.server) {
|
|
228
|
-
resolve();
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
this.logger.info('Stopping server...');
|
|
232
|
-
// Set timeout for force shutdown
|
|
233
|
-
const forceShutdownTimer = setTimeout(() => {
|
|
234
|
-
this.logger.warn('Force closing server after timeout');
|
|
235
|
-
this.server?.close();
|
|
236
|
-
resolve();
|
|
237
|
-
}, timeout);
|
|
238
|
-
this.server?.close((error) => {
|
|
239
|
-
clearTimeout(forceShutdownTimer);
|
|
240
|
-
if (error) {
|
|
241
|
-
this.logger.error('Error stopping server', error);
|
|
242
|
-
reject(error);
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
this.logger.info('Server stopped');
|
|
246
|
-
this.emit('stopped');
|
|
247
|
-
resolve();
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
// Allow subclasses to cleanup
|
|
251
|
-
this.onStop();
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* Hook called when server is stopping
|
|
256
|
-
* Override this to cleanup resources, close connections, etc.
|
|
257
|
-
*/
|
|
258
|
-
onStop() {
|
|
259
|
-
// Override in subclasses if needed
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* Get the Express application
|
|
263
|
-
* @returns The Express app instance
|
|
264
|
-
*/
|
|
265
|
-
getApp() {
|
|
266
|
-
return this.app;
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Get the HTTP server
|
|
270
|
-
* @returns The HTTP server instance
|
|
271
|
-
*/
|
|
272
|
-
getServer() {
|
|
273
|
-
return this.server;
|
|
274
|
-
}
|
|
275
|
-
/**
|
|
276
|
-
* Check if server is running
|
|
277
|
-
* @returns True if server is running
|
|
278
|
-
*/
|
|
279
|
-
isRunning() {
|
|
280
|
-
return !!this.server?.listening;
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Get server configuration
|
|
284
|
-
* @returns The server configuration
|
|
285
|
-
*/
|
|
286
|
-
getConfig() {
|
|
287
|
-
return { ...this.config };
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
export default BaseAPIServer;
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* POSIX Brace Expansion Implementation
|
|
3
|
-
* Handles patterns like {a,b,c}, {1..5}, {a..z}, etc.
|
|
4
|
-
*/
|
|
5
|
-
export class BraceExpander {
|
|
6
|
-
maxExpansions;
|
|
7
|
-
constructor(options = {}) {
|
|
8
|
-
this.maxExpansions = options.maxExpansions || 10000;
|
|
9
|
-
}
|
|
10
|
-
expandBraces(pattern) {
|
|
11
|
-
// If no braces, return as-is
|
|
12
|
-
if (!pattern.includes('{') || !pattern.includes('}')) {
|
|
13
|
-
return [pattern];
|
|
14
|
-
}
|
|
15
|
-
try {
|
|
16
|
-
const results = this.expandPattern(pattern);
|
|
17
|
-
// Safety check to prevent excessive expansions
|
|
18
|
-
if (results.length > this.maxExpansions) {
|
|
19
|
-
return [pattern]; // Return original if too many expansions
|
|
20
|
-
}
|
|
21
|
-
return results;
|
|
22
|
-
}
|
|
23
|
-
catch (_error) {
|
|
24
|
-
// If expansion fails, return original pattern
|
|
25
|
-
return [pattern];
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
expandPattern(pattern) {
|
|
29
|
-
// Find the first complete brace expression
|
|
30
|
-
const braceMatch = this.findBraceExpression(pattern);
|
|
31
|
-
if (!braceMatch) {
|
|
32
|
-
return [pattern];
|
|
33
|
-
}
|
|
34
|
-
const { start, end, content } = braceMatch;
|
|
35
|
-
const prefix = pattern.substring(0, start);
|
|
36
|
-
const suffix = pattern.substring(end + 1);
|
|
37
|
-
// Expand the brace content
|
|
38
|
-
const expansions = this.expandBraceContent(content);
|
|
39
|
-
// Combine prefix + expansion + suffix
|
|
40
|
-
const results = [];
|
|
41
|
-
for (const expansion of expansions) {
|
|
42
|
-
const combined = prefix + expansion + suffix;
|
|
43
|
-
// Recursively expand any remaining braces
|
|
44
|
-
const furtherExpanded = this.expandPattern(combined);
|
|
45
|
-
results.push(...furtherExpanded);
|
|
46
|
-
}
|
|
47
|
-
return results;
|
|
48
|
-
}
|
|
49
|
-
findBraceExpression(pattern) {
|
|
50
|
-
let braceCount = 0;
|
|
51
|
-
let start = -1;
|
|
52
|
-
for (let i = 0; i < pattern.length; i++) {
|
|
53
|
-
const char = pattern[i];
|
|
54
|
-
if (char === '{') {
|
|
55
|
-
if (braceCount === 0) {
|
|
56
|
-
start = i;
|
|
57
|
-
}
|
|
58
|
-
braceCount++;
|
|
59
|
-
}
|
|
60
|
-
else if (char === '}') {
|
|
61
|
-
braceCount--;
|
|
62
|
-
if (braceCount === 0 && start !== -1) {
|
|
63
|
-
const content = pattern.substring(start + 1, i);
|
|
64
|
-
return { start, end: i, content };
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
expandBraceContent(content) {
|
|
71
|
-
// Handle sequence expansion first (e.g., 1..5, a..z)
|
|
72
|
-
const sequenceMatch = content.match(/^(.+?)\.\.(.+?)(?:\.\.(.+))?$/);
|
|
73
|
-
if (sequenceMatch) {
|
|
74
|
-
return this.expandSequence(sequenceMatch[1], sequenceMatch[2], sequenceMatch[3]);
|
|
75
|
-
}
|
|
76
|
-
// Handle comma-separated list (e.g., a,b,c)
|
|
77
|
-
if (content.includes(',')) {
|
|
78
|
-
return this.expandCommaList(content);
|
|
79
|
-
}
|
|
80
|
-
// Not a valid brace expression
|
|
81
|
-
return ['{' + content + '}'];
|
|
82
|
-
}
|
|
83
|
-
expandSequence(start, end, step) {
|
|
84
|
-
const results = [];
|
|
85
|
-
// Determine if numeric or alphabetic sequence
|
|
86
|
-
const startNum = parseInt(start, 10);
|
|
87
|
-
const endNum = parseInt(end, 10);
|
|
88
|
-
const stepNum = step ? parseInt(step, 10) : 1;
|
|
89
|
-
if (!isNaN(startNum) && !isNaN(endNum)) {
|
|
90
|
-
// Numeric sequence
|
|
91
|
-
if (stepNum <= 0)
|
|
92
|
-
return ['{' + start + '..' + end + '}'];
|
|
93
|
-
if (startNum <= endNum) {
|
|
94
|
-
for (let i = startNum; i <= endNum; i += stepNum) {
|
|
95
|
-
results.push(i.toString());
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
for (let i = startNum; i >= endNum; i -= stepNum) {
|
|
100
|
-
results.push(i.toString());
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
else if (start.length === 1 && end.length === 1) {
|
|
105
|
-
// Alphabetic sequence
|
|
106
|
-
const startCode = start.charCodeAt(0);
|
|
107
|
-
const endCode = end.charCodeAt(0);
|
|
108
|
-
if (startCode <= endCode) {
|
|
109
|
-
for (let i = startCode; i <= endCode; i += stepNum) {
|
|
110
|
-
results.push(String.fromCharCode(i));
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
for (let i = startCode; i >= endCode; i -= stepNum) {
|
|
115
|
-
results.push(String.fromCharCode(i));
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
// Invalid sequence
|
|
121
|
-
return ['{' + start + '..' + end + '}'];
|
|
122
|
-
}
|
|
123
|
-
return results;
|
|
124
|
-
}
|
|
125
|
-
expandCommaList(content) {
|
|
126
|
-
const results = [];
|
|
127
|
-
let current = '';
|
|
128
|
-
let braceCount = 0;
|
|
129
|
-
for (let i = 0; i < content.length; i++) {
|
|
130
|
-
const char = content[i];
|
|
131
|
-
if (char === '{') {
|
|
132
|
-
braceCount++;
|
|
133
|
-
current += char;
|
|
134
|
-
}
|
|
135
|
-
else if (char === '}') {
|
|
136
|
-
braceCount--;
|
|
137
|
-
current += char;
|
|
138
|
-
}
|
|
139
|
-
else if (char === ',' && braceCount === 0) {
|
|
140
|
-
results.push(current.trim());
|
|
141
|
-
current = '';
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
current += char;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
if (current) {
|
|
148
|
-
results.push(current.trim());
|
|
149
|
-
}
|
|
150
|
-
return results;
|
|
151
|
-
}
|
|
152
|
-
// Utility method for expanding multiple patterns
|
|
153
|
-
expandMultiplePatterns(patterns) {
|
|
154
|
-
const results = [];
|
|
155
|
-
for (const pattern of patterns) {
|
|
156
|
-
results.push(...this.expandBraces(pattern));
|
|
157
|
-
}
|
|
158
|
-
return results;
|
|
159
|
-
}
|
|
160
|
-
}
|