hispano-lang 1.0.8 → 2.0.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 +637 -237
- package/dist/evaluator.js +1395 -259
- package/dist/parser.js +646 -201
- package/dist/tokenizer.js +199 -121
- package/package.json +12 -3
package/dist/tokenizer.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
class Tokenizer {
|
|
7
7
|
constructor() {
|
|
8
|
-
this.source =
|
|
8
|
+
this.source = "";
|
|
9
9
|
this.tokens = [];
|
|
10
10
|
this.current = 0;
|
|
11
11
|
this.startPos = 0;
|
|
@@ -27,8 +27,8 @@ class Tokenizer {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
this.tokens.push({
|
|
30
|
-
type:
|
|
31
|
-
lexeme:
|
|
30
|
+
type: "EOF",
|
|
31
|
+
lexeme: "",
|
|
32
32
|
literal: null,
|
|
33
33
|
line: this.currentLine,
|
|
34
34
|
});
|
|
@@ -43,8 +43,8 @@ class Tokenizer {
|
|
|
43
43
|
|
|
44
44
|
// Check for comments before advancing
|
|
45
45
|
if (
|
|
46
|
-
this.source[this.current] ===
|
|
47
|
-
this.source[this.current + 1] ===
|
|
46
|
+
this.source[this.current] === "/" &&
|
|
47
|
+
this.source[this.current + 1] === "/"
|
|
48
48
|
) {
|
|
49
49
|
this.comment();
|
|
50
50
|
return;
|
|
@@ -53,141 +53,141 @@ class Tokenizer {
|
|
|
53
53
|
const char = this.advance();
|
|
54
54
|
|
|
55
55
|
switch (char) {
|
|
56
|
-
case
|
|
57
|
-
case
|
|
58
|
-
case
|
|
56
|
+
case " ":
|
|
57
|
+
case "\r":
|
|
58
|
+
case "\t":
|
|
59
59
|
// Ignore whitespace
|
|
60
60
|
break;
|
|
61
61
|
|
|
62
|
-
case
|
|
62
|
+
case "\n":
|
|
63
63
|
this.currentLine++;
|
|
64
64
|
break;
|
|
65
65
|
|
|
66
|
-
case
|
|
67
|
-
if (this.peek() ===
|
|
66
|
+
case "=":
|
|
67
|
+
if (this.peek() === "=") {
|
|
68
68
|
this.advance();
|
|
69
|
-
this.addToken(
|
|
69
|
+
this.addToken("EQUAL_EQUAL");
|
|
70
70
|
} else {
|
|
71
|
-
this.addToken(
|
|
71
|
+
this.addToken("EQUAL");
|
|
72
72
|
}
|
|
73
73
|
break;
|
|
74
74
|
|
|
75
|
-
case
|
|
76
|
-
if (this.peek() ===
|
|
75
|
+
case "*":
|
|
76
|
+
if (this.peek() === "=") {
|
|
77
77
|
this.advance();
|
|
78
|
-
this.addToken(
|
|
78
|
+
this.addToken("STAR_EQUAL");
|
|
79
79
|
} else {
|
|
80
|
-
this.addToken(
|
|
80
|
+
this.addToken("STAR");
|
|
81
81
|
}
|
|
82
82
|
break;
|
|
83
83
|
|
|
84
|
-
case
|
|
85
|
-
if (this.peek() ===
|
|
84
|
+
case "/":
|
|
85
|
+
if (this.peek() === "=") {
|
|
86
86
|
this.advance();
|
|
87
|
-
this.addToken(
|
|
87
|
+
this.addToken("SLASH_EQUAL");
|
|
88
88
|
} else {
|
|
89
|
-
this.addToken(
|
|
89
|
+
this.addToken("SLASH");
|
|
90
90
|
}
|
|
91
91
|
break;
|
|
92
92
|
|
|
93
|
-
case
|
|
94
|
-
if (this.peek() ===
|
|
93
|
+
case "%":
|
|
94
|
+
if (this.peek() === "=") {
|
|
95
95
|
this.advance();
|
|
96
|
-
this.addToken(
|
|
96
|
+
this.addToken("PERCENT_EQUAL");
|
|
97
97
|
} else {
|
|
98
|
-
this.addToken(
|
|
98
|
+
this.addToken("PERCENT");
|
|
99
99
|
}
|
|
100
100
|
break;
|
|
101
101
|
|
|
102
|
-
case
|
|
103
|
-
if (this.peek() ===
|
|
102
|
+
case ">":
|
|
103
|
+
if (this.peek() === "=") {
|
|
104
104
|
this.advance();
|
|
105
|
-
this.addToken(
|
|
105
|
+
this.addToken("GREATER_EQUAL");
|
|
106
106
|
} else {
|
|
107
|
-
this.addToken(
|
|
107
|
+
this.addToken("GREATER");
|
|
108
108
|
}
|
|
109
109
|
break;
|
|
110
110
|
|
|
111
|
-
case
|
|
112
|
-
if (this.peek() ===
|
|
111
|
+
case "<":
|
|
112
|
+
if (this.peek() === "=") {
|
|
113
113
|
this.advance();
|
|
114
|
-
this.addToken(
|
|
114
|
+
this.addToken("LESS_EQUAL");
|
|
115
115
|
} else {
|
|
116
|
-
this.addToken(
|
|
116
|
+
this.addToken("LESS");
|
|
117
117
|
}
|
|
118
118
|
break;
|
|
119
119
|
|
|
120
|
-
case
|
|
121
|
-
if (this.peek() ===
|
|
120
|
+
case "!":
|
|
121
|
+
if (this.peek() === "=") {
|
|
122
122
|
this.advance();
|
|
123
|
-
this.addToken(
|
|
123
|
+
this.addToken("BANG_EQUAL");
|
|
124
124
|
} else {
|
|
125
|
-
this.addToken(
|
|
125
|
+
this.addToken("BANG");
|
|
126
126
|
}
|
|
127
127
|
break;
|
|
128
128
|
|
|
129
|
-
case
|
|
130
|
-
if (this.peek() ===
|
|
129
|
+
case "+":
|
|
130
|
+
if (this.peek() === "+") {
|
|
131
131
|
this.advance();
|
|
132
|
-
this.addToken(
|
|
133
|
-
} else if (this.peek() ===
|
|
132
|
+
this.addToken("PLUS_PLUS");
|
|
133
|
+
} else if (this.peek() === "=") {
|
|
134
134
|
this.advance();
|
|
135
|
-
this.addToken(
|
|
135
|
+
this.addToken("PLUS_EQUAL");
|
|
136
136
|
} else {
|
|
137
|
-
this.addToken(
|
|
137
|
+
this.addToken("PLUS");
|
|
138
138
|
}
|
|
139
139
|
break;
|
|
140
140
|
|
|
141
|
-
case
|
|
142
|
-
if (this.peek() ===
|
|
141
|
+
case "-":
|
|
142
|
+
if (this.peek() === "-") {
|
|
143
143
|
this.advance();
|
|
144
|
-
this.addToken(
|
|
145
|
-
} else if (this.peek() ===
|
|
144
|
+
this.addToken("MINUS_MINUS");
|
|
145
|
+
} else if (this.peek() === "=") {
|
|
146
146
|
this.advance();
|
|
147
|
-
this.addToken(
|
|
147
|
+
this.addToken("MINUS_EQUAL");
|
|
148
148
|
} else {
|
|
149
|
-
this.addToken(
|
|
149
|
+
this.addToken("MINUS");
|
|
150
150
|
}
|
|
151
151
|
break;
|
|
152
152
|
|
|
153
|
-
case
|
|
154
|
-
this.addToken(
|
|
153
|
+
case "{":
|
|
154
|
+
this.addToken("LEFT_BRACE");
|
|
155
155
|
break;
|
|
156
156
|
|
|
157
|
-
case
|
|
158
|
-
this.addToken(
|
|
157
|
+
case "}":
|
|
158
|
+
this.addToken("RIGHT_BRACE");
|
|
159
159
|
break;
|
|
160
160
|
|
|
161
|
-
case
|
|
162
|
-
this.addToken(
|
|
161
|
+
case "(":
|
|
162
|
+
this.addToken("LEFT_PAREN");
|
|
163
163
|
break;
|
|
164
164
|
|
|
165
|
-
case
|
|
166
|
-
this.addToken(
|
|
165
|
+
case ")":
|
|
166
|
+
this.addToken("RIGHT_PAREN");
|
|
167
167
|
break;
|
|
168
168
|
|
|
169
|
-
case
|
|
170
|
-
this.addToken(
|
|
169
|
+
case ",":
|
|
170
|
+
this.addToken("COMMA");
|
|
171
171
|
break;
|
|
172
172
|
|
|
173
|
-
case
|
|
174
|
-
this.addToken(
|
|
173
|
+
case ";":
|
|
174
|
+
this.addToken("SEMICOLON");
|
|
175
175
|
break;
|
|
176
176
|
|
|
177
|
-
case
|
|
178
|
-
this.addToken(
|
|
177
|
+
case ":":
|
|
178
|
+
this.addToken("COLON");
|
|
179
179
|
break;
|
|
180
180
|
|
|
181
|
-
case
|
|
182
|
-
this.addToken(
|
|
181
|
+
case "[":
|
|
182
|
+
this.addToken("LEFT_BRACKET");
|
|
183
183
|
break;
|
|
184
184
|
|
|
185
|
-
case
|
|
186
|
-
this.addToken(
|
|
185
|
+
case "]":
|
|
186
|
+
this.addToken("RIGHT_BRACKET");
|
|
187
187
|
break;
|
|
188
188
|
|
|
189
|
-
case
|
|
190
|
-
this.addToken(
|
|
189
|
+
case ".":
|
|
190
|
+
this.addToken("DOT");
|
|
191
191
|
break;
|
|
192
192
|
|
|
193
193
|
case '"':
|
|
@@ -198,11 +198,15 @@ class Tokenizer {
|
|
|
198
198
|
this.string("'");
|
|
199
199
|
break;
|
|
200
200
|
|
|
201
|
-
case
|
|
202
|
-
|
|
201
|
+
case "`":
|
|
202
|
+
this.templateString();
|
|
203
|
+
break;
|
|
204
|
+
|
|
205
|
+
case "/":
|
|
206
|
+
if (this.peek() === "/") {
|
|
203
207
|
this.comment();
|
|
204
208
|
} else {
|
|
205
|
-
this.addToken(
|
|
209
|
+
this.addToken("SLASH");
|
|
206
210
|
}
|
|
207
211
|
break;
|
|
208
212
|
|
|
@@ -213,7 +217,7 @@ class Tokenizer {
|
|
|
213
217
|
this.identifier();
|
|
214
218
|
} else {
|
|
215
219
|
throw new Error(
|
|
216
|
-
`Carácter inesperado: ${char} en la línea ${this.currentLine}
|
|
220
|
+
`Carácter inesperado: ${char} en la línea ${this.currentLine}`,
|
|
217
221
|
);
|
|
218
222
|
}
|
|
219
223
|
break;
|
|
@@ -226,12 +230,12 @@ class Tokenizer {
|
|
|
226
230
|
*/
|
|
227
231
|
string(quoteType = '"') {
|
|
228
232
|
while (this.peek() !== quoteType && !this.isAtEnd()) {
|
|
229
|
-
if (this.peek() ===
|
|
233
|
+
if (this.peek() === "\n") this.currentLine++;
|
|
230
234
|
this.advance();
|
|
231
235
|
}
|
|
232
236
|
|
|
233
237
|
if (this.isAtEnd()) {
|
|
234
|
-
throw new Error(
|
|
238
|
+
throw new Error("Cadena no terminada");
|
|
235
239
|
}
|
|
236
240
|
|
|
237
241
|
// Consume the closing quote
|
|
@@ -239,7 +243,68 @@ class Tokenizer {
|
|
|
239
243
|
|
|
240
244
|
// Extract the string value
|
|
241
245
|
const value = this.source.substring(this.startPos + 1, this.current - 1);
|
|
242
|
-
this.addToken(
|
|
246
|
+
this.addToken("STRING", value);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Processes a template string with interpolation (backticks)
|
|
251
|
+
* Supports ${expression} syntax for embedding expressions
|
|
252
|
+
*/
|
|
253
|
+
templateString() {
|
|
254
|
+
const parts = []; // Literal string parts
|
|
255
|
+
const expressions = []; // Expression source strings
|
|
256
|
+
let currentPart = "";
|
|
257
|
+
|
|
258
|
+
while (!this.isAtEnd()) {
|
|
259
|
+
const char = this.peek();
|
|
260
|
+
|
|
261
|
+
if (char === "`") {
|
|
262
|
+
// End of template string
|
|
263
|
+
this.advance();
|
|
264
|
+
parts.push(currentPart);
|
|
265
|
+
this.addToken("TEMPLATE_STRING", { parts, expressions });
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (char === "$" && this.peekNext() === "{") {
|
|
270
|
+
// Start of interpolation
|
|
271
|
+
parts.push(currentPart);
|
|
272
|
+
currentPart = "";
|
|
273
|
+
this.advance(); // consume $
|
|
274
|
+
this.advance(); // consume {
|
|
275
|
+
|
|
276
|
+
// Extract the expression
|
|
277
|
+
let braceCount = 1;
|
|
278
|
+
let expressionSource = "";
|
|
279
|
+
|
|
280
|
+
while (!this.isAtEnd() && braceCount > 0) {
|
|
281
|
+
const c = this.peek();
|
|
282
|
+
if (c === "{") {
|
|
283
|
+
braceCount++;
|
|
284
|
+
expressionSource += c;
|
|
285
|
+
this.advance();
|
|
286
|
+
} else if (c === "}") {
|
|
287
|
+
braceCount--;
|
|
288
|
+
if (braceCount > 0) {
|
|
289
|
+
expressionSource += c;
|
|
290
|
+
}
|
|
291
|
+
this.advance();
|
|
292
|
+
} else {
|
|
293
|
+
if (c === "\n") this.currentLine++;
|
|
294
|
+
expressionSource += c;
|
|
295
|
+
this.advance();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
expressions.push(expressionSource);
|
|
300
|
+
} else {
|
|
301
|
+
if (char === "\n") this.currentLine++;
|
|
302
|
+
currentPart += char;
|
|
303
|
+
this.advance();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
throw new Error("Cadena de plantilla no terminada");
|
|
243
308
|
}
|
|
244
309
|
|
|
245
310
|
/**
|
|
@@ -250,7 +315,7 @@ class Tokenizer {
|
|
|
250
315
|
this.advance();
|
|
251
316
|
|
|
252
317
|
// Skip until end of line
|
|
253
|
-
while (this.peek() !==
|
|
318
|
+
while (this.peek() !== "\n" && !this.isAtEnd()) {
|
|
254
319
|
this.advance();
|
|
255
320
|
}
|
|
256
321
|
|
|
@@ -267,7 +332,7 @@ class Tokenizer {
|
|
|
267
332
|
}
|
|
268
333
|
|
|
269
334
|
// Look for decimal part
|
|
270
|
-
if (this.peek() ===
|
|
335
|
+
if (this.peek() === "." && this.isDigit(this.peekNext())) {
|
|
271
336
|
// Consume the dot
|
|
272
337
|
this.advance();
|
|
273
338
|
|
|
@@ -277,7 +342,7 @@ class Tokenizer {
|
|
|
277
342
|
}
|
|
278
343
|
|
|
279
344
|
const value = this.source.substring(this.startPos, this.current);
|
|
280
|
-
this.addToken(
|
|
345
|
+
this.addToken("NUMBER", parseFloat(value));
|
|
281
346
|
}
|
|
282
347
|
|
|
283
348
|
/**
|
|
@@ -285,7 +350,7 @@ class Tokenizer {
|
|
|
285
350
|
* @returns {string} Next character
|
|
286
351
|
*/
|
|
287
352
|
peekNext() {
|
|
288
|
-
if (this.current + 1 >= this.source.length) return
|
|
353
|
+
if (this.current + 1 >= this.source.length) return "\0";
|
|
289
354
|
return this.source[this.current + 1];
|
|
290
355
|
}
|
|
291
356
|
|
|
@@ -300,36 +365,36 @@ class Tokenizer {
|
|
|
300
365
|
const text = this.source.substring(this.startPos, this.current);
|
|
301
366
|
|
|
302
367
|
// Special handling for 'y' - only treat as AND in logical contexts
|
|
303
|
-
if (text ===
|
|
368
|
+
if (text === "y") {
|
|
304
369
|
// Check if this is a logical context by looking at previous tokens
|
|
305
370
|
const prevToken = this.tokens[this.tokens.length - 1];
|
|
306
371
|
if (
|
|
307
372
|
prevToken &&
|
|
308
|
-
(prevToken.type ===
|
|
309
|
-
prevToken.type ===
|
|
310
|
-
prevToken.type ===
|
|
311
|
-
prevToken.type ===
|
|
312
|
-
prevToken.type ===
|
|
313
|
-
prevToken.type ===
|
|
314
|
-
prevToken.type ===
|
|
373
|
+
(prevToken.type === "IDENTIFIER" ||
|
|
374
|
+
prevToken.type === "NUMBER" ||
|
|
375
|
+
prevToken.type === "STRING" ||
|
|
376
|
+
prevToken.type === "TRUE" ||
|
|
377
|
+
prevToken.type === "FALSE" ||
|
|
378
|
+
prevToken.type === "RIGHT_PAREN" ||
|
|
379
|
+
prevToken.type === "RIGHT_BRACKET")
|
|
315
380
|
) {
|
|
316
381
|
// Check if the next token is a logical operator or end of expression
|
|
317
382
|
const nextChar = this.peek();
|
|
318
383
|
if (
|
|
319
|
-
nextChar ===
|
|
320
|
-
nextChar ===
|
|
321
|
-
nextChar ===
|
|
322
|
-
nextChar ===
|
|
323
|
-
nextChar ===
|
|
324
|
-
nextChar ===
|
|
384
|
+
nextChar === " " ||
|
|
385
|
+
nextChar === "\n" ||
|
|
386
|
+
nextChar === "\t" ||
|
|
387
|
+
nextChar === ")" ||
|
|
388
|
+
nextChar === "}" ||
|
|
389
|
+
nextChar === ";" ||
|
|
325
390
|
this.isAtEnd()
|
|
326
391
|
) {
|
|
327
|
-
this.addToken(
|
|
392
|
+
this.addToken("AND");
|
|
328
393
|
} else {
|
|
329
|
-
this.addToken(
|
|
394
|
+
this.addToken("IDENTIFIER");
|
|
330
395
|
}
|
|
331
396
|
} else {
|
|
332
|
-
this.addToken(
|
|
397
|
+
this.addToken("IDENTIFIER");
|
|
333
398
|
}
|
|
334
399
|
} else {
|
|
335
400
|
const type = this.getKeywordType(text);
|
|
@@ -344,27 +409,40 @@ class Tokenizer {
|
|
|
344
409
|
*/
|
|
345
410
|
getKeywordType(text) {
|
|
346
411
|
const keywords = {
|
|
347
|
-
variable:
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
412
|
+
variable: "VARIABLE",
|
|
413
|
+
constante: "CONSTANTE",
|
|
414
|
+
mostrar: "MOSTRAR",
|
|
415
|
+
leer: "LEER",
|
|
416
|
+
si: "SI",
|
|
417
|
+
sino: "SINO",
|
|
418
|
+
mientras: "MIENTRAS",
|
|
419
|
+
para: "PARA",
|
|
420
|
+
funcion: "FUNCION",
|
|
421
|
+
retornar: "RETORNAR",
|
|
422
|
+
verdadero: "TRUE",
|
|
423
|
+
falso: "FALSE",
|
|
424
|
+
o: "OR",
|
|
425
|
+
romper: "ROMPER",
|
|
426
|
+
continuar: "CONTINUAR",
|
|
427
|
+
intentar: "INTENTAR",
|
|
428
|
+
capturar: "CAPTURAR",
|
|
429
|
+
nulo: "NULL",
|
|
430
|
+
indefinido: "UNDEFINED",
|
|
431
|
+
elegir: "ELEGIR",
|
|
432
|
+
caso: "CASO",
|
|
433
|
+
pordefecto: "PORDEFECTO",
|
|
434
|
+
hacer: "HACER",
|
|
435
|
+
cada: "CADA",
|
|
436
|
+
en: "EN",
|
|
437
|
+
clase: "CLASE",
|
|
438
|
+
constructor: "CONSTRUCTOR",
|
|
439
|
+
este: "ESTE",
|
|
440
|
+
nuevo: "NUEVO",
|
|
441
|
+
extiende: "EXTIENDE",
|
|
442
|
+
super: "SUPER",
|
|
365
443
|
};
|
|
366
444
|
|
|
367
|
-
return keywords[text] ||
|
|
445
|
+
return keywords[text] || "IDENTIFIER";
|
|
368
446
|
}
|
|
369
447
|
|
|
370
448
|
/**
|
|
@@ -388,7 +466,7 @@ class Tokenizer {
|
|
|
388
466
|
* @returns {string} Current character
|
|
389
467
|
*/
|
|
390
468
|
peek() {
|
|
391
|
-
if (this.isAtEnd()) return
|
|
469
|
+
if (this.isAtEnd()) return "\0";
|
|
392
470
|
return this.source[this.current];
|
|
393
471
|
}
|
|
394
472
|
|
|
@@ -406,7 +484,7 @@ class Tokenizer {
|
|
|
406
484
|
* @returns {boolean} True if it is a digit
|
|
407
485
|
*/
|
|
408
486
|
isDigit(char) {
|
|
409
|
-
return char >=
|
|
487
|
+
return char >= "0" && char <= "9";
|
|
410
488
|
}
|
|
411
489
|
|
|
412
490
|
/**
|
|
@@ -416,9 +494,9 @@ class Tokenizer {
|
|
|
416
494
|
*/
|
|
417
495
|
isAlpha(char) {
|
|
418
496
|
return (
|
|
419
|
-
(char >=
|
|
420
|
-
(char >=
|
|
421
|
-
char ===
|
|
497
|
+
(char >= "a" && char <= "z") ||
|
|
498
|
+
(char >= "A" && char <= "Z") ||
|
|
499
|
+
char === "_"
|
|
422
500
|
);
|
|
423
501
|
}
|
|
424
502
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hispano-lang",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Un lenguaje de programación educativo en español para enseñar programación sin barreras de idioma",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"build:types": "mkdir -p dist && node scripts/generate-types.js",
|
|
27
27
|
"demo": "node main.js",
|
|
28
28
|
"prepublishOnly": "npm run build",
|
|
29
|
-
"prepack": "npm run build"
|
|
29
|
+
"prepack": "npm run build",
|
|
30
|
+
"prepare": "husky"
|
|
30
31
|
},
|
|
31
32
|
"keywords": [
|
|
32
33
|
"programming-language",
|
|
@@ -58,8 +59,10 @@
|
|
|
58
59
|
},
|
|
59
60
|
"homepage": "https://github.com/nicvazquezdev/hispano-lang#readme",
|
|
60
61
|
"devDependencies": {
|
|
61
|
-
"nodemon": "^3.1.10",
|
|
62
62
|
"eslint": "^8.57.0",
|
|
63
|
+
"husky": "^9.1.7",
|
|
64
|
+
"lint-staged": "^16.2.7",
|
|
65
|
+
"nodemon": "^3.1.10",
|
|
63
66
|
"prettier": "^3.2.5"
|
|
64
67
|
},
|
|
65
68
|
"dependencies": {
|
|
@@ -68,5 +71,11 @@
|
|
|
68
71
|
"preferGlobal": true,
|
|
69
72
|
"publishConfig": {
|
|
70
73
|
"access": "public"
|
|
74
|
+
},
|
|
75
|
+
"lint-staged": {
|
|
76
|
+
"*.js": [
|
|
77
|
+
"eslint --fix",
|
|
78
|
+
"prettier --write"
|
|
79
|
+
]
|
|
71
80
|
}
|
|
72
81
|
}
|