lsh-framework 1.2.0 → 1.3.0
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/fuzzy-match.js +123 -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 +119 -59
- 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,185 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* API Error Handler
|
|
3
|
-
* Consolidates error response formatting across all API endpoints
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* HTTP status codes for common error types
|
|
7
|
-
*/
|
|
8
|
-
export const ErrorStatusCodes = {
|
|
9
|
-
BAD_REQUEST: 400,
|
|
10
|
-
UNAUTHORIZED: 401,
|
|
11
|
-
FORBIDDEN: 403,
|
|
12
|
-
NOT_FOUND: 404,
|
|
13
|
-
CONFLICT: 409,
|
|
14
|
-
INTERNAL_SERVER_ERROR: 500,
|
|
15
|
-
SERVICE_UNAVAILABLE: 503,
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Custom API Error class with status code
|
|
19
|
-
*/
|
|
20
|
-
export class ApiError extends Error {
|
|
21
|
-
statusCode;
|
|
22
|
-
code;
|
|
23
|
-
details;
|
|
24
|
-
constructor(message, statusCode = ErrorStatusCodes.INTERNAL_SERVER_ERROR, code, details) {
|
|
25
|
-
super(message);
|
|
26
|
-
this.statusCode = statusCode;
|
|
27
|
-
this.code = code;
|
|
28
|
-
this.details = details;
|
|
29
|
-
this.name = 'ApiError';
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Send error response with consistent formatting
|
|
34
|
-
*
|
|
35
|
-
* @param res - Express response object
|
|
36
|
-
* @param error - Error object
|
|
37
|
-
* @param statusCode - HTTP status code (default: 500)
|
|
38
|
-
*/
|
|
39
|
-
export function sendError(res, error, statusCode) {
|
|
40
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
41
|
-
const status = statusCode || (err instanceof ApiError ? err.statusCode : 500);
|
|
42
|
-
const response = {
|
|
43
|
-
error: err.message || 'An unexpected error occurred',
|
|
44
|
-
timestamp: new Date().toISOString(),
|
|
45
|
-
};
|
|
46
|
-
if (err instanceof ApiError) {
|
|
47
|
-
if (err.code)
|
|
48
|
-
response.code = err.code;
|
|
49
|
-
if (err.details)
|
|
50
|
-
response.details = err.details;
|
|
51
|
-
}
|
|
52
|
-
// Log error for debugging (in production, use proper logger)
|
|
53
|
-
if (status >= 500) {
|
|
54
|
-
console.error('API Error:', err);
|
|
55
|
-
}
|
|
56
|
-
res.status(status).json(response);
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Send success response with consistent formatting
|
|
60
|
-
*
|
|
61
|
-
* @param res - Express response object
|
|
62
|
-
* @param data - Response data
|
|
63
|
-
* @param statusCode - HTTP status code (default: 200)
|
|
64
|
-
* @param includeTimestamp - Include timestamp in response
|
|
65
|
-
*/
|
|
66
|
-
export function sendSuccess(res, data, statusCode = 200, includeTimestamp = false) {
|
|
67
|
-
if (statusCode === 204) {
|
|
68
|
-
res.status(204).send();
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
const response = includeTimestamp
|
|
72
|
-
? { data, timestamp: new Date().toISOString() }
|
|
73
|
-
: data;
|
|
74
|
-
res.status(statusCode).json(response);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Wrapper for async route handlers with automatic error handling
|
|
78
|
-
*
|
|
79
|
-
* Eliminates the need for try-catch blocks in every route handler
|
|
80
|
-
*
|
|
81
|
-
* @param handler - Async route handler function
|
|
82
|
-
* @returns Express middleware function
|
|
83
|
-
*
|
|
84
|
-
* @example
|
|
85
|
-
* ```typescript
|
|
86
|
-
* app.get('/api/jobs', asyncHandler(async (req, res) => {
|
|
87
|
-
* const jobs = await getJobs();
|
|
88
|
-
* sendSuccess(res, jobs);
|
|
89
|
-
* }));
|
|
90
|
-
* ```
|
|
91
|
-
*/
|
|
92
|
-
export function asyncHandler(handler) {
|
|
93
|
-
return (req, res, next) => {
|
|
94
|
-
Promise.resolve(handler(req, res, next)).catch((error) => {
|
|
95
|
-
sendError(res, error);
|
|
96
|
-
});
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Execute an operation with automatic success/error handling
|
|
101
|
-
*
|
|
102
|
-
* This is the most powerful wrapper - it handles:
|
|
103
|
-
* - Try-catch
|
|
104
|
-
* - Success response formatting
|
|
105
|
-
* - Error response formatting
|
|
106
|
-
* - Optional webhook triggering
|
|
107
|
-
*
|
|
108
|
-
* @param res - Express response object
|
|
109
|
-
* @param operation - Async operation to execute
|
|
110
|
-
* @param config - Configuration options
|
|
111
|
-
* @param webhookTrigger - Optional webhook trigger function
|
|
112
|
-
*
|
|
113
|
-
* @example
|
|
114
|
-
* ```typescript
|
|
115
|
-
* app.post('/api/jobs', async (req, res) => {
|
|
116
|
-
* await handleApiOperation(
|
|
117
|
-
* res,
|
|
118
|
-
* async () => this.daemon.addJob(req.body),
|
|
119
|
-
* {
|
|
120
|
-
* successStatus: 201,
|
|
121
|
-
* webhookEvent: 'job.created'
|
|
122
|
-
* },
|
|
123
|
-
* (event, data) => this.triggerWebhook(event, data)
|
|
124
|
-
* );
|
|
125
|
-
* });
|
|
126
|
-
* ```
|
|
127
|
-
*/
|
|
128
|
-
export async function handleApiOperation(res, operation, config = {}, webhookTrigger) {
|
|
129
|
-
const { successStatus = 200, includeTimestamp = false, webhookEvent, webhookData, } = config;
|
|
130
|
-
try {
|
|
131
|
-
const result = await operation();
|
|
132
|
-
// Send success response
|
|
133
|
-
sendSuccess(res, result, successStatus, includeTimestamp);
|
|
134
|
-
// Trigger webhook if configured
|
|
135
|
-
if (webhookEvent && webhookTrigger) {
|
|
136
|
-
const webhookPayload = webhookData ? webhookData(result) : result;
|
|
137
|
-
webhookTrigger(webhookEvent, webhookPayload);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
catch (error) {
|
|
141
|
-
const err = error;
|
|
142
|
-
// Determine appropriate status code
|
|
143
|
-
let statusCode = 400;
|
|
144
|
-
if (err instanceof ApiError) {
|
|
145
|
-
statusCode = err.statusCode;
|
|
146
|
-
}
|
|
147
|
-
else if (err.message.includes('not found') || err.message.includes('Not found')) {
|
|
148
|
-
statusCode = 404;
|
|
149
|
-
}
|
|
150
|
-
else if (err.message.includes('permission') || err.message.includes('unauthorized')) {
|
|
151
|
-
statusCode = 403;
|
|
152
|
-
}
|
|
153
|
-
else if (err.message.includes('exists') || err.message.includes('duplicate')) {
|
|
154
|
-
statusCode = 409;
|
|
155
|
-
}
|
|
156
|
-
sendError(res, err, statusCode);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Create a typed API handler with webhook support
|
|
161
|
-
*
|
|
162
|
-
* Returns a function that can be used to handle API operations with
|
|
163
|
-
* automatic error handling and webhook triggering
|
|
164
|
-
*
|
|
165
|
-
* @param webhookTrigger - Webhook trigger function
|
|
166
|
-
* @returns Handler function
|
|
167
|
-
*/
|
|
168
|
-
export function createApiHandler(webhookTrigger) {
|
|
169
|
-
return async function (res, operation, config = {}) {
|
|
170
|
-
await handleApiOperation(res, operation, config, webhookTrigger);
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Express error handling middleware
|
|
175
|
-
*
|
|
176
|
-
* Should be added after all routes
|
|
177
|
-
*
|
|
178
|
-
* @example
|
|
179
|
-
* ```typescript
|
|
180
|
-
* app.use(errorMiddleware);
|
|
181
|
-
* ```
|
|
182
|
-
*/
|
|
183
|
-
export function errorMiddleware(error, req, res, _next) {
|
|
184
|
-
sendError(res, error);
|
|
185
|
-
}
|
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Associative Arrays Implementation
|
|
3
|
-
* Provides ZSH-compatible associative array functionality
|
|
4
|
-
*/
|
|
5
|
-
export class AssociativeArrayManager {
|
|
6
|
-
context;
|
|
7
|
-
constructor() {
|
|
8
|
-
this.context = {
|
|
9
|
-
arrays: new Map(),
|
|
10
|
-
arrayTypes: new Map(),
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Declare an associative array with typeset -A
|
|
15
|
-
*/
|
|
16
|
-
declareAssociativeArray(name) {
|
|
17
|
-
this.context.arrays.set(name, {});
|
|
18
|
-
this.context.arrayTypes.set(name, 'associative');
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Declare an indexed array with typeset -a
|
|
22
|
-
*/
|
|
23
|
-
declareIndexedArray(name) {
|
|
24
|
-
this.context.arrays.set(name, {});
|
|
25
|
-
this.context.arrayTypes.set(name, 'indexed');
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Set a value in an associative array
|
|
29
|
-
*/
|
|
30
|
-
setAssociativeValue(arrayName, key, value) {
|
|
31
|
-
if (!this.context.arrays.has(arrayName)) {
|
|
32
|
-
this.declareAssociativeArray(arrayName);
|
|
33
|
-
}
|
|
34
|
-
const array = this.context.arrays.get(arrayName);
|
|
35
|
-
array[key] = value;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Set a value in an indexed array
|
|
39
|
-
*/
|
|
40
|
-
setIndexedValue(arrayName, index, value) {
|
|
41
|
-
if (!this.context.arrays.has(arrayName)) {
|
|
42
|
-
this.declareIndexedArray(arrayName);
|
|
43
|
-
}
|
|
44
|
-
const array = this.context.arrays.get(arrayName);
|
|
45
|
-
array[index.toString()] = value;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Get a value from an array
|
|
49
|
-
*/
|
|
50
|
-
getValue(arrayName, key) {
|
|
51
|
-
const array = this.context.arrays.get(arrayName);
|
|
52
|
-
return array ? array[key] : undefined;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Get all keys from an associative array
|
|
56
|
-
*/
|
|
57
|
-
getKeys(arrayName) {
|
|
58
|
-
const array = this.context.arrays.get(arrayName);
|
|
59
|
-
if (!array)
|
|
60
|
-
return [];
|
|
61
|
-
const type = this.context.arrayTypes.get(arrayName);
|
|
62
|
-
if (type === 'indexed') {
|
|
63
|
-
// For indexed arrays, return sorted numeric keys
|
|
64
|
-
return Object.keys(array)
|
|
65
|
-
.map(k => parseInt(k, 10))
|
|
66
|
-
.filter(k => !isNaN(k))
|
|
67
|
-
.sort((a, b) => a - b)
|
|
68
|
-
.map(k => k.toString());
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
// For associative arrays, return all keys
|
|
72
|
-
return Object.keys(array);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Get all values from an array
|
|
77
|
-
*/
|
|
78
|
-
getValues(arrayName) {
|
|
79
|
-
const array = this.context.arrays.get(arrayName);
|
|
80
|
-
if (!array)
|
|
81
|
-
return [];
|
|
82
|
-
const type = this.context.arrayTypes.get(arrayName);
|
|
83
|
-
if (type === 'indexed') {
|
|
84
|
-
// For indexed arrays, return values in order
|
|
85
|
-
const keys = this.getKeys(arrayName);
|
|
86
|
-
return keys.map(key => array[key]);
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
// For associative arrays, return all values
|
|
90
|
-
return Object.values(array);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Get array length
|
|
95
|
-
*/
|
|
96
|
-
getLength(arrayName) {
|
|
97
|
-
const array = this.context.arrays.get(arrayName);
|
|
98
|
-
return array ? Object.keys(array).length : 0;
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Check if an array exists
|
|
102
|
-
*/
|
|
103
|
-
hasArray(arrayName) {
|
|
104
|
-
return this.context.arrays.has(arrayName);
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Get array type
|
|
108
|
-
*/
|
|
109
|
-
getArrayType(arrayName) {
|
|
110
|
-
return this.context.arrayTypes.get(arrayName);
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Remove an array
|
|
114
|
-
*/
|
|
115
|
-
removeArray(arrayName) {
|
|
116
|
-
const hadArray = this.context.arrays.has(arrayName);
|
|
117
|
-
this.context.arrays.delete(arrayName);
|
|
118
|
-
this.context.arrayTypes.delete(arrayName);
|
|
119
|
-
return hadArray;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Get all array names
|
|
123
|
-
*/
|
|
124
|
-
getAllArrayNames() {
|
|
125
|
-
return Array.from(this.context.arrays.keys());
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Clear all arrays
|
|
129
|
-
*/
|
|
130
|
-
clearAllArrays() {
|
|
131
|
-
this.context.arrays.clear();
|
|
132
|
-
this.context.arrayTypes.clear();
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Get array slice (for indexed arrays)
|
|
136
|
-
*/
|
|
137
|
-
getSlice(arrayName, start, end) {
|
|
138
|
-
const array = this.context.arrays.get(arrayName);
|
|
139
|
-
if (!array)
|
|
140
|
-
return [];
|
|
141
|
-
const type = this.context.arrayTypes.get(arrayName);
|
|
142
|
-
if (type !== 'indexed')
|
|
143
|
-
return [];
|
|
144
|
-
const keys = this.getKeys(arrayName);
|
|
145
|
-
const startIdx = Math.max(0, start - 1); // Convert to 0-based
|
|
146
|
-
const endIdx = end ? Math.min(keys.length, end) : keys.length;
|
|
147
|
-
return keys.slice(startIdx, endIdx).map(key => array[key]);
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Expand array reference like ${array[key]} or ${array[@]}
|
|
151
|
-
*/
|
|
152
|
-
expandArrayReference(reference) {
|
|
153
|
-
// Match patterns like ${array[key]}, ${array[@]}, ${array[*]}
|
|
154
|
-
const match = reference.match(/^\$\{([^[\]]+)(?:\[([^\]]+)\])?(?:\[@\*\]|\[@\]|\[\*\]|\[@\])?\}$/);
|
|
155
|
-
if (!match)
|
|
156
|
-
return [];
|
|
157
|
-
const arrayName = match[1];
|
|
158
|
-
const key = match[2];
|
|
159
|
-
if (!this.hasArray(arrayName))
|
|
160
|
-
return [];
|
|
161
|
-
if (key) {
|
|
162
|
-
// Single element access
|
|
163
|
-
const value = this.getValue(arrayName, key);
|
|
164
|
-
return value !== undefined ? [value] : [];
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
// All elements access
|
|
168
|
-
return this.getValues(arrayName);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Expand array keys like ${(k)array}
|
|
173
|
-
*/
|
|
174
|
-
expandArrayKeys(reference) {
|
|
175
|
-
const match = reference.match(/^\$\{\(k\)([^}]+)\}$/);
|
|
176
|
-
if (!match)
|
|
177
|
-
return [];
|
|
178
|
-
const arrayName = match[1];
|
|
179
|
-
return this.getKeys(arrayName);
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Expand array values like ${(v)array}
|
|
183
|
-
*/
|
|
184
|
-
expandArrayValues(reference) {
|
|
185
|
-
const match = reference.match(/^\$\{\(v\)([^}]+)\}$/);
|
|
186
|
-
if (!match)
|
|
187
|
-
return [];
|
|
188
|
-
const arrayName = match[1];
|
|
189
|
-
return this.getValues(arrayName);
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Expand array length like ${#array}
|
|
193
|
-
*/
|
|
194
|
-
expandArrayLength(reference) {
|
|
195
|
-
const match = reference.match(/^\$\{#([^}]+)\}$/);
|
|
196
|
-
if (!match)
|
|
197
|
-
return '';
|
|
198
|
-
const arrayName = match[1];
|
|
199
|
-
return this.getLength(arrayName).toString();
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Parse typeset command
|
|
203
|
-
*/
|
|
204
|
-
parseTypesetCommand(args) {
|
|
205
|
-
if (args.length === 0) {
|
|
206
|
-
return { success: false, message: 'typeset: missing arguments' };
|
|
207
|
-
}
|
|
208
|
-
for (const arg of args) {
|
|
209
|
-
if (arg === '-A') {
|
|
210
|
-
// Declare associative array - next argument should be the name
|
|
211
|
-
const nameIndex = args.indexOf('-A') + 1;
|
|
212
|
-
if (nameIndex < args.length) {
|
|
213
|
-
const name = args[nameIndex];
|
|
214
|
-
this.declareAssociativeArray(name);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
else if (arg === '-a') {
|
|
218
|
-
// Declare indexed array - next argument should be the name
|
|
219
|
-
const nameIndex = args.indexOf('-a') + 1;
|
|
220
|
-
if (nameIndex < args.length) {
|
|
221
|
-
const name = args[nameIndex];
|
|
222
|
-
this.declareIndexedArray(name);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
else if (arg.includes('=')) {
|
|
226
|
-
// Assignment: name=value or name[key]=value
|
|
227
|
-
const [left, right] = arg.split('=', 2);
|
|
228
|
-
const arrayMatch = left.match(/^([^[\]]+)(?:\[([^\]]+)\])?$/);
|
|
229
|
-
if (arrayMatch) {
|
|
230
|
-
const arrayName = arrayMatch[1];
|
|
231
|
-
const key = arrayMatch[2];
|
|
232
|
-
if (key) {
|
|
233
|
-
// Associative array assignment
|
|
234
|
-
this.setAssociativeValue(arrayName, key, right);
|
|
235
|
-
}
|
|
236
|
-
else {
|
|
237
|
-
// Regular variable assignment (not array)
|
|
238
|
-
// This would be handled by the regular variable system
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
return { success: true, message: '' };
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Get array information for display
|
|
247
|
-
*/
|
|
248
|
-
getArrayInfo(arrayName) {
|
|
249
|
-
if (!this.hasArray(arrayName))
|
|
250
|
-
return null;
|
|
251
|
-
const type = this.getArrayType(arrayName);
|
|
252
|
-
const length = this.getLength(arrayName);
|
|
253
|
-
const keys = this.getKeys(arrayName);
|
|
254
|
-
const values = this.getValues(arrayName);
|
|
255
|
-
return {
|
|
256
|
-
type: type || 'unknown',
|
|
257
|
-
length,
|
|
258
|
-
keys,
|
|
259
|
-
values,
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Export array data for serialization
|
|
264
|
-
*/
|
|
265
|
-
exportArrays() {
|
|
266
|
-
const arrays = {};
|
|
267
|
-
const types = {};
|
|
268
|
-
for (const [name, array] of this.context.arrays) {
|
|
269
|
-
arrays[name] = { ...array };
|
|
270
|
-
types[name] = this.context.arrayTypes.get(name) || 'unknown';
|
|
271
|
-
}
|
|
272
|
-
return { arrays, types };
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Import array data from serialization
|
|
276
|
-
*/
|
|
277
|
-
importArrays(data) {
|
|
278
|
-
this.clearAllArrays();
|
|
279
|
-
for (const [name, array] of Object.entries(data.arrays)) {
|
|
280
|
-
this.context.arrays.set(name, { ...array });
|
|
281
|
-
this.context.arrayTypes.set(name, data.types[name]);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
export default AssociativeArrayManager;
|