vladx 1.0.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.
@@ -0,0 +1,476 @@
1
+ /**
2
+ * VladX Parser
3
+ * Parser ricorsivo discendente per generare AST
4
+ */
5
+
6
+ const { TokenType } = require('../lexer/tokens.js');
7
+ const AST = require('./ast.js');
8
+
9
+ class ParserError extends Error {
10
+ constructor(message, token) {
11
+ super(`Errore alla riga ${token.line}, colonna ${token.column}: ${message}`);
12
+ this.token = token;
13
+ }
14
+ }
15
+
16
+ class Parser {
17
+ constructor(tokens) {
18
+ this.tokens = tokens;
19
+ this.current = 0;
20
+ }
21
+
22
+ // === Utility Methods ===
23
+ peek() {
24
+ return this.tokens[this.current];
25
+ }
26
+
27
+ previous() {
28
+ return this.tokens[this.current - 1];
29
+ }
30
+
31
+ isAtEnd() {
32
+ return this.peek().type === TokenType.FINE;
33
+ }
34
+
35
+ advance() {
36
+ if (!this.isAtEnd()) this.current++;
37
+ return this.previous();
38
+ }
39
+
40
+ check(type) {
41
+ if (this.isAtEnd()) return false;
42
+ return this.peek().type === type;
43
+ }
44
+
45
+ match(...types) {
46
+ for (const type of types) {
47
+ if (this.check(type)) {
48
+ this.advance();
49
+ return true;
50
+ }
51
+ }
52
+ return false;
53
+ }
54
+
55
+ consume(type, message) {
56
+ if (this.check(type)) return this.advance();
57
+ throw new ParserError(message, this.peek());
58
+ }
59
+
60
+ // === Parsing Methods ===
61
+ parse() {
62
+ const statements = [];
63
+ while (!this.isAtEnd()) {
64
+ const stmt = this.declaration();
65
+ if (stmt) statements.push(stmt);
66
+ }
67
+ return new AST.Program(statements);
68
+ }
69
+
70
+ declaration() {
71
+ try {
72
+ if (this.match(TokenType.VARIABILE)) return this.variableDeclaration(false);
73
+ if (this.match(TokenType.COSTANTE)) return this.variableDeclaration(true);
74
+ if (this.match(TokenType.FUNZIONE)) return this.functionDeclaration();
75
+ return this.statement();
76
+ } catch (error) {
77
+ this.synchronize();
78
+ throw error;
79
+ }
80
+ }
81
+
82
+ variableDeclaration(isConstant) {
83
+ const name = this.consume(TokenType.IDENTIFICATORE, 'Nome variabile atteso').value;
84
+ let value = null;
85
+ if (this.match(TokenType.ASSEGNA)) {
86
+ value = this.expression();
87
+ }
88
+ this.match(TokenType.PUNTO_VIRGOLA);
89
+ return new AST.VariableDeclaration(name, value, isConstant);
90
+ }
91
+
92
+ functionDeclaration() {
93
+ const name = this.consume(TokenType.IDENTIFICATORE, 'Nome funzione atteso').value;
94
+ this.consume(TokenType.PARENTESI_APERTA, 'Atteso "(" dopo nome funzione');
95
+ const params = [];
96
+ if (!this.check(TokenType.PARENTESI_CHIUSA)) {
97
+ do {
98
+ params.push(this.consume(TokenType.IDENTIFICATORE, 'Nome parametro atteso').value);
99
+ } while (this.match(TokenType.VIRGOLA));
100
+ }
101
+ this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo parametri');
102
+ this.consume(TokenType.GRAFFA_APERTA, 'Atteso "{" prima del corpo funzione');
103
+ const body = this.blockStatement();
104
+ return new AST.FunctionDeclaration(name, params, body);
105
+ }
106
+
107
+ statement() {
108
+ if (this.match(TokenType.SE)) return this.ifStatement();
109
+ if (this.match(TokenType.MENTRE)) return this.whileStatement();
110
+ if (this.match(TokenType.PER)) return this.forStatement();
111
+ if (this.match(TokenType.RITORNA)) return this.returnStatement();
112
+ if (this.match(TokenType.INTERROMPI)) return this.breakStatement();
113
+ if (this.match(TokenType.CONTINUA)) return this.continueStatement();
114
+ if (this.match(TokenType.STAMPA)) return this.printStatement();
115
+ if (this.match(TokenType.GRAFFA_APERTA)) return this.blockStatement();
116
+ return this.expressionStatement();
117
+ }
118
+
119
+ blockStatement() {
120
+ const statements = [];
121
+ while (!this.check(TokenType.GRAFFA_CHIUSA) && !this.isAtEnd()) {
122
+ statements.push(this.declaration());
123
+ }
124
+ this.consume(TokenType.GRAFFA_CHIUSA, 'Atteso "}" alla fine del blocco');
125
+ return new AST.BlockStatement(statements);
126
+ }
127
+
128
+ ifStatement() {
129
+ this.consume(TokenType.PARENTESI_APERTA, 'Atteso "(" dopo "se"');
130
+ const condition = this.expression();
131
+ this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo condizione');
132
+ this.consume(TokenType.GRAFFA_APERTA, 'Atteso "{" dopo condizione');
133
+ const consequent = this.blockStatement();
134
+ let alternate = null;
135
+ if (this.match(TokenType.ALTRIMENTI)) {
136
+ if (this.match(TokenType.SE)) {
137
+ alternate = this.ifStatement();
138
+ } else {
139
+ this.consume(TokenType.GRAFFA_APERTA, 'Atteso "{" dopo "altrimenti"');
140
+ alternate = this.blockStatement();
141
+ }
142
+ }
143
+ return new AST.IfStatement(condition, consequent, alternate);
144
+ }
145
+
146
+ whileStatement() {
147
+ this.consume(TokenType.PARENTESI_APERTA, 'Atteso "(" dopo "mentre"');
148
+ const condition = this.expression();
149
+ this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo condizione');
150
+ this.consume(TokenType.GRAFFA_APERTA, 'Atteso "{" dopo condizione');
151
+ const body = this.blockStatement();
152
+ return new AST.WhileStatement(condition, body);
153
+ }
154
+
155
+ forStatement() {
156
+ this.consume(TokenType.PARENTESI_APERTA, 'Atteso "(" dopo "per"');
157
+
158
+ let init = null;
159
+ if (this.match(TokenType.VARIABILE)) {
160
+ init = this.variableDeclaration(false);
161
+ } else if (!this.check(TokenType.PUNTO_VIRGOLA)) {
162
+ init = this.expressionStatement();
163
+ } else {
164
+ this.advance();
165
+ }
166
+
167
+ let condition = null;
168
+ if (!this.check(TokenType.PUNTO_VIRGOLA)) {
169
+ condition = this.expression();
170
+ }
171
+ this.consume(TokenType.PUNTO_VIRGOLA, 'Atteso ";" dopo condizione del ciclo');
172
+
173
+ let update = null;
174
+ if (!this.check(TokenType.PARENTESI_CHIUSA)) {
175
+ update = this.expression();
176
+ }
177
+ this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo clausole del ciclo');
178
+
179
+ this.consume(TokenType.GRAFFA_APERTA, 'Atteso "{" dopo clausole del ciclo');
180
+ const body = this.blockStatement();
181
+ return new AST.ForStatement(init, condition, update, body);
182
+ }
183
+
184
+ returnStatement() {
185
+ let argument = null;
186
+ if (!this.check(TokenType.PUNTO_VIRGOLA) && !this.check(TokenType.GRAFFA_CHIUSA)) {
187
+ argument = this.expression();
188
+ }
189
+ this.match(TokenType.PUNTO_VIRGOLA);
190
+ return new AST.ReturnStatement(argument);
191
+ }
192
+
193
+ breakStatement() {
194
+ this.match(TokenType.PUNTO_VIRGOLA);
195
+ return new AST.BreakStatement();
196
+ }
197
+
198
+ continueStatement() {
199
+ this.match(TokenType.PUNTO_VIRGOLA);
200
+ return new AST.ContinueStatement();
201
+ }
202
+
203
+ printStatement() {
204
+ this.consume(TokenType.PARENTESI_APERTA, 'Atteso "(" dopo "stampa"');
205
+ const argument = this.expression();
206
+ this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo argomento');
207
+ this.match(TokenType.PUNTO_VIRGOLA);
208
+ return new AST.PrintStatement(argument);
209
+ }
210
+
211
+ expressionStatement() {
212
+ const expr = this.expression();
213
+ this.match(TokenType.PUNTO_VIRGOLA);
214
+ return new AST.ExpressionStatement(expr);
215
+ }
216
+
217
+ // === Expression Parsing (Precedence Climbing) ===
218
+ expression() {
219
+ return this.assignment();
220
+ }
221
+
222
+ assignment() {
223
+ const expr = this.logicalOr();
224
+
225
+ if (this.match(TokenType.ASSEGNA, TokenType.PIU_ASSEGNA, TokenType.MENO_ASSEGNA)) {
226
+ const operator = this.previous().value;
227
+ const value = this.assignment();
228
+ return new AST.AssignmentExpression(operator, expr, value);
229
+ }
230
+
231
+ return expr;
232
+ }
233
+
234
+ logicalOr() {
235
+ let expr = this.logicalAnd();
236
+
237
+ while (this.match(TokenType.O, TokenType.OR)) {
238
+ const operator = '||';
239
+ const right = this.logicalAnd();
240
+ expr = new AST.LogicalExpression(operator, expr, right);
241
+ }
242
+
243
+ return expr;
244
+ }
245
+
246
+ logicalAnd() {
247
+ let expr = this.equality();
248
+
249
+ while (this.match(TokenType.E, TokenType.AND)) {
250
+ const operator = '&&';
251
+ const right = this.equality();
252
+ expr = new AST.LogicalExpression(operator, expr, right);
253
+ }
254
+
255
+ return expr;
256
+ }
257
+
258
+ equality() {
259
+ let expr = this.comparison();
260
+
261
+ while (this.match(TokenType.UGUALE, TokenType.DIVERSO, TokenType.UGUALE_STRETTO, TokenType.DIVERSO_STRETTO)) {
262
+ const operator = this.previous().value;
263
+ const right = this.comparison();
264
+ expr = new AST.BinaryExpression(operator, expr, right);
265
+ }
266
+
267
+ return expr;
268
+ }
269
+
270
+ comparison() {
271
+ let expr = this.term();
272
+
273
+ while (this.match(TokenType.MINORE, TokenType.MAGGIORE, TokenType.MINORE_UGUALE, TokenType.MAGGIORE_UGUALE)) {
274
+ const operator = this.previous().value;
275
+ const right = this.term();
276
+ expr = new AST.BinaryExpression(operator, expr, right);
277
+ }
278
+
279
+ return expr;
280
+ }
281
+
282
+ term() {
283
+ let expr = this.factor();
284
+
285
+ while (this.match(TokenType.PIU, TokenType.MENO)) {
286
+ const operator = this.previous().value;
287
+ const right = this.factor();
288
+ expr = new AST.BinaryExpression(operator, expr, right);
289
+ }
290
+
291
+ return expr;
292
+ }
293
+
294
+ factor() {
295
+ let expr = this.unary();
296
+
297
+ while (this.match(TokenType.MOLTIPLICA, TokenType.DIVIDI, TokenType.MODULO)) {
298
+ const operator = this.previous().value;
299
+ const right = this.unary();
300
+ expr = new AST.BinaryExpression(operator, expr, right);
301
+ }
302
+
303
+ return expr;
304
+ }
305
+
306
+ unary() {
307
+ if (this.match(TokenType.NON, TokenType.MENO)) {
308
+ const operator = this.previous().value === 'non' ? '!' : this.previous().value;
309
+ const argument = this.unary();
310
+ return new AST.UnaryExpression(operator, argument);
311
+ }
312
+
313
+ return this.postfix();
314
+ }
315
+
316
+ postfix() {
317
+ let expr = this.call();
318
+
319
+ while (this.match(TokenType.INCREMENTA, TokenType.DECREMENTA)) {
320
+ const operator = this.previous().value;
321
+ expr = new AST.UpdateExpression(operator, expr, false);
322
+ }
323
+
324
+ return expr;
325
+ }
326
+
327
+ call() {
328
+ let expr = this.primary();
329
+
330
+ while (true) {
331
+ if (this.match(TokenType.PARENTESI_APERTA)) {
332
+ expr = this.finishCall(expr);
333
+ } else if (this.match(TokenType.PUNTO)) {
334
+ const property = this.consume(TokenType.IDENTIFICATORE, 'Nome proprietà atteso dopo "."');
335
+ expr = new AST.MemberExpression(expr, new AST.Identifier(property.value), false);
336
+ } else if (this.match(TokenType.QUADRA_APERTA)) {
337
+ const property = this.expression();
338
+ this.consume(TokenType.QUADRA_CHIUSA, 'Atteso "]" dopo indice');
339
+ expr = new AST.MemberExpression(expr, property, true);
340
+ } else {
341
+ break;
342
+ }
343
+ }
344
+
345
+ return expr;
346
+ }
347
+
348
+ finishCall(callee) {
349
+ const args = [];
350
+ if (!this.check(TokenType.PARENTESI_CHIUSA)) {
351
+ do {
352
+ args.push(this.expression());
353
+ } while (this.match(TokenType.VIRGOLA));
354
+ }
355
+ this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo argomenti');
356
+ return new AST.CallExpression(callee, args);
357
+ }
358
+
359
+ primary() {
360
+ if (this.match(TokenType.VERO)) return new AST.BooleanLiteral(true);
361
+ if (this.match(TokenType.FALSO)) return new AST.BooleanLiteral(false);
362
+ if (this.match(TokenType.NULLO)) return new AST.NullLiteral();
363
+
364
+ if (this.match(TokenType.NUMERO)) {
365
+ return new AST.NumericLiteral(this.previous().value);
366
+ }
367
+
368
+ if (this.match(TokenType.STRINGA)) {
369
+ return new AST.StringLiteral(this.previous().value);
370
+ }
371
+
372
+ if (this.match(TokenType.IDENTIFICATORE)) {
373
+ return new AST.Identifier(this.previous().value);
374
+ }
375
+
376
+ if (this.match(TokenType.QUESTO)) {
377
+ return new AST.Identifier('questo');
378
+ }
379
+
380
+ if (this.match(TokenType.QUADRA_APERTA)) {
381
+ return this.arrayLiteral();
382
+ }
383
+
384
+ if (this.match(TokenType.GRAFFA_APERTA)) {
385
+ return this.objectLiteral();
386
+ }
387
+
388
+ if (this.match(TokenType.PARENTESI_APERTA)) {
389
+ // Potrebbe essere una arrow function o un'espressione raggruppata
390
+ const startPos = this.current - 1;
391
+
392
+ // Prova a parsare come arrow function
393
+ if (this.check(TokenType.PARENTESI_CHIUSA) || this.check(TokenType.IDENTIFICATORE)) {
394
+ const params = [];
395
+ if (!this.check(TokenType.PARENTESI_CHIUSA)) {
396
+ do {
397
+ if (this.match(TokenType.IDENTIFICATORE)) {
398
+ params.push(this.previous().value);
399
+ } else {
400
+ // Non è una arrow function, torna indietro
401
+ this.current = startPos + 1;
402
+ const expr = this.expression();
403
+ this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo espressione');
404
+ return expr;
405
+ }
406
+ } while (this.match(TokenType.VIRGOLA));
407
+ }
408
+
409
+ if (this.match(TokenType.PARENTESI_CHIUSA) && this.match(TokenType.FRECCIA)) {
410
+ // È una arrow function
411
+ if (this.match(TokenType.GRAFFA_APERTA)) {
412
+ const body = this.blockStatement();
413
+ return new AST.ArrowFunction(params, body);
414
+ } else {
415
+ const body = this.expression();
416
+ return new AST.ArrowFunction(params, body);
417
+ }
418
+ } else {
419
+ // Non è una arrow function, torna indietro
420
+ this.current = startPos + 1;
421
+ }
422
+ }
423
+
424
+ const expr = this.expression();
425
+ this.consume(TokenType.PARENTESI_CHIUSA, 'Atteso ")" dopo espressione');
426
+ return expr;
427
+ }
428
+
429
+ throw new ParserError(`Token inaspettato: ${this.peek().type}`, this.peek());
430
+ }
431
+
432
+ arrayLiteral() {
433
+ const elements = [];
434
+ if (!this.check(TokenType.QUADRA_CHIUSA)) {
435
+ do {
436
+ elements.push(this.expression());
437
+ } while (this.match(TokenType.VIRGOLA));
438
+ }
439
+ this.consume(TokenType.QUADRA_CHIUSA, 'Atteso "]" alla fine dell\'array');
440
+ return new AST.ArrayLiteral(elements);
441
+ }
442
+
443
+ objectLiteral() {
444
+ const properties = [];
445
+ if (!this.check(TokenType.GRAFFA_CHIUSA)) {
446
+ do {
447
+ const key = this.consume(TokenType.IDENTIFICATORE, 'Nome proprietà atteso').value;
448
+ this.consume(TokenType.DUE_PUNTI, 'Atteso ":" dopo nome proprietà');
449
+ const value = this.expression();
450
+ properties.push(new AST.Property(key, value));
451
+ } while (this.match(TokenType.VIRGOLA));
452
+ }
453
+ this.consume(TokenType.GRAFFA_CHIUSA, 'Atteso "}" alla fine dell\'oggetto');
454
+ return new AST.ObjectLiteral(properties);
455
+ }
456
+
457
+ synchronize() {
458
+ this.advance();
459
+ while (!this.isAtEnd()) {
460
+ if (this.previous().type === TokenType.PUNTO_VIRGOLA) return;
461
+ switch (this.peek().type) {
462
+ case TokenType.FUNZIONE:
463
+ case TokenType.VARIABILE:
464
+ case TokenType.COSTANTE:
465
+ case TokenType.PER:
466
+ case TokenType.SE:
467
+ case TokenType.MENTRE:
468
+ case TokenType.RITORNA:
469
+ return;
470
+ }
471
+ this.advance();
472
+ }
473
+ }
474
+ }
475
+
476
+ module.exports = { Parser, ParserError };
package/src/pm/cli.js ADDED
@@ -0,0 +1,130 @@
1
+ /**
2
+ * VladPM CLI
3
+ * Package Manager per VladX
4
+ */
5
+
6
+ const init = require('./commands/init.js');
7
+ const login = require('./commands/login.js');
8
+ const publish = require('./commands/publish.js');
9
+ const install = require('./commands/install.js');
10
+ const uninstall = require('./commands/uninstall.js');
11
+ const search = require('./commands/search.js');
12
+ const list = require('./commands/list.js');
13
+ const config = require('./commands/config.js');
14
+
15
+ const VERSION = '1.0.0';
16
+
17
+ const COLORS = {
18
+ reset: '\x1b[0m',
19
+ bright: '\x1b[1m',
20
+ red: '\x1b[31m',
21
+ green: '\x1b[32m',
22
+ yellow: '\x1b[33m',
23
+ cyan: '\x1b[36m'
24
+ };
25
+
26
+ function colorize(text, color) {
27
+ return `${COLORS[color]}${text}${COLORS.reset}`;
28
+ }
29
+
30
+ function showHelp() {
31
+ console.log(`
32
+ ${colorize('VladPM', 'bright')} - Package Manager per VladX
33
+
34
+ ${colorize('Uso:', 'cyan')}
35
+ vladpm init Inizializza un nuovo progetto
36
+ vladpm login Login al registry
37
+ vladpm logout Logout dal registry
38
+ vladpm publish Pubblica il pacchetto
39
+ vladpm install [pkg] Installa un pacchetto (o tutti da vladx.json)
40
+ vladpm uninstall <pkg> Rimuove un pacchetto
41
+ vladpm search <query> Cerca pacchetti
42
+ vladpm list Lista pacchetti installati
43
+ vladpm --help, -h Mostra questo aiuto
44
+ vladpm --version, -v Mostra la versione
45
+
46
+ ${colorize('Esempi:', 'cyan')}
47
+ vladpm init
48
+ vladpm install mio-pacchetto
49
+ vladpm publish
50
+ `);
51
+ }
52
+
53
+ function showVersion() {
54
+ console.log(`VladPM v${VERSION}`);
55
+ }
56
+
57
+ async function run(args) {
58
+ if (args.length === 0) {
59
+ showHelp();
60
+ return;
61
+ }
62
+
63
+ const command = args[0];
64
+
65
+ try {
66
+ switch (command) {
67
+ case '--help':
68
+ case '-h':
69
+ case 'help':
70
+ showHelp();
71
+ break;
72
+
73
+ case '--version':
74
+ case '-v':
75
+ case 'version':
76
+ showVersion();
77
+ break;
78
+
79
+ case 'init':
80
+ await init.execute(args.slice(1));
81
+ break;
82
+
83
+ case 'login':
84
+ await login.execute(args.slice(1));
85
+ break;
86
+
87
+ case 'logout':
88
+ await login.logout();
89
+ break;
90
+
91
+ case 'publish':
92
+ await publish.execute(args.slice(1));
93
+ break;
94
+
95
+ case 'install':
96
+ case 'i':
97
+ await install.execute(args.slice(1));
98
+ break;
99
+
100
+ case 'uninstall':
101
+ case 'remove':
102
+ case 'rm':
103
+ await uninstall.execute(args.slice(1));
104
+ break;
105
+
106
+ case 'search':
107
+ await search.execute(args.slice(1));
108
+ break;
109
+
110
+ case 'list':
111
+ case 'ls':
112
+ await list.execute(args.slice(1));
113
+ break;
114
+
115
+ case 'config':
116
+ await config.execute(args.slice(1));
117
+ break;
118
+
119
+ default:
120
+ console.error(colorize(`✗ Comando sconosciuto: ${command}`, 'red'));
121
+ console.log('Usa "vladpm --help" per vedere i comandi disponibili.');
122
+ process.exit(1);
123
+ }
124
+ } catch (error) {
125
+ console.error(colorize(`✗ Errore: ${error.message}`, 'red'));
126
+ process.exit(1);
127
+ }
128
+ }
129
+
130
+ module.exports = { run };
@@ -0,0 +1,76 @@
1
+ /**
2
+ * VladPM - config command
3
+ */
4
+
5
+ const { getConfig, saveConfig, getRegistry } = require('../utils/config.js');
6
+
7
+ const COLORS = {
8
+ reset: '\x1b[0m',
9
+ bright: '\x1b[1m',
10
+ green: '\x1b[32m',
11
+ cyan: '\x1b[36m',
12
+ yellow: '\x1b[33m'
13
+ };
14
+
15
+ function colorize(text, color) {
16
+ return `${COLORS[color]}${text}${COLORS.reset}`;
17
+ }
18
+
19
+ async function execute(args) {
20
+ if (args.length === 0) {
21
+ // Show current config
22
+ console.log(colorize('\n⚙️ Configurazione VladPM\n', 'bright'));
23
+ const config = getConfig();
24
+ console.log(` Registry: ${colorize(config.registry || 'default', 'cyan')}`);
25
+ if (config.username) {
26
+ console.log(` Utente: ${colorize(config.username, 'cyan')}`);
27
+ }
28
+ console.log();
29
+ return;
30
+ }
31
+
32
+ const subcommand = args[0];
33
+
34
+ if (subcommand === 'set') {
35
+ const key = args[1];
36
+ const value = args[2];
37
+
38
+ if (!key || !value) {
39
+ console.log(colorize('Uso: vladpm config set <chiave> <valore>', 'yellow'));
40
+ console.log('\nChiavi disponibili:');
41
+ console.log(' registry URL del registry (es: http://localhost:3000)');
42
+ return;
43
+ }
44
+
45
+ const config = getConfig();
46
+
47
+ if (key === 'registry') {
48
+ config.registry = value;
49
+ saveConfig(config);
50
+ console.log(colorize(`✓ Registry impostato a: ${value}`, 'green'));
51
+ } else {
52
+ console.log(colorize(`✗ Chiave sconosciuta: ${key}`, 'yellow'));
53
+ }
54
+ } else if (subcommand === 'get') {
55
+ const key = args[1];
56
+ const config = getConfig();
57
+
58
+ if (key === 'registry') {
59
+ console.log(getRegistry());
60
+ } else if (key) {
61
+ console.log(config[key] || '');
62
+ } else {
63
+ console.log(JSON.stringify(config, null, 2));
64
+ }
65
+ } else if (subcommand === 'reset') {
66
+ const config = getConfig();
67
+ delete config.registry;
68
+ saveConfig(config);
69
+ console.log(colorize('✓ Configurazione resettata ai valori di default', 'green'));
70
+ } else {
71
+ console.log(colorize(`Sottocomando sconosciuto: ${subcommand}`, 'yellow'));
72
+ console.log('Usa: vladpm config [set|get|reset]');
73
+ }
74
+ }
75
+
76
+ module.exports = { execute };