@slim-lang/core 1.2.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.
Files changed (52) hide show
  1. package/README.md +666 -0
  2. package/package.json +55 -0
  3. package/packages/slim/.spm +7 -0
  4. package/packages/slim/converters/main.slim +106 -0
  5. package/packages/slim/helpers/array.slim +25 -0
  6. package/packages/slim/helpers/path.slim +3 -0
  7. package/packages/slim/helpers/request.slim +102 -0
  8. package/packages/slim/helpers/string.slim +27 -0
  9. package/packages/slim/main.slim +42 -0
  10. package/packages/slim/parse/main.slim +25 -0
  11. package/packages/slim/server/main.slim +423 -0
  12. package/packages/slim/time/main.slim +66 -0
  13. package/packages/slim/types/common.slim +6 -0
  14. package/packages/slim/types/formats.slim +23 -0
  15. package/packages/slim/types/hash.slim +6 -0
  16. package/packages/slim/types/mails.slim +3 -0
  17. package/packages/slim/types/numerical.slim +9 -0
  18. package/packages/slim/types/time.slim +3 -0
  19. package/run-dev-slim.js +133 -0
  20. package/run-slim.js +20 -0
  21. package/src/bin/api/github_auth.js +89 -0
  22. package/src/bin/api/github_get.js +139 -0
  23. package/src/bin/api/github_req.js +455 -0
  24. package/src/bin/api/lock.js +37 -0
  25. package/src/bin/api/spm.js +103 -0
  26. package/src/bin/api/storage.js +30 -0
  27. package/src/bin/cli.js +404 -0
  28. package/src/bin/config.default.json +5 -0
  29. package/src/bin/helpers.js +147 -0
  30. package/src/bin/parsers/spm.js +174 -0
  31. package/src/bin/spm.js +519 -0
  32. package/src/checker.js +926 -0
  33. package/src/compile.js +230 -0
  34. package/src/external/classErrors.js +202 -0
  35. package/src/external/client.js +38 -0
  36. package/src/external/core.js +861 -0
  37. package/src/external/defaults.js +25 -0
  38. package/src/external/helpers.js +541 -0
  39. package/src/external/slim-globals.d.ts +65 -0
  40. package/src/external/types.js +38 -0
  41. package/src/format.js +81 -0
  42. package/src/handlers/errorHandler.js +43 -0
  43. package/src/handlers/parser/components.js +250 -0
  44. package/src/handlers/parserHandler.js +793 -0
  45. package/src/jsdoc.js +273 -0
  46. package/src/lexer.js +174 -0
  47. package/src/modulePaths.js +74 -0
  48. package/src/parser.js +818 -0
  49. package/src/repl.js +32 -0
  50. package/src/sourcemap.js +0 -0
  51. package/src/test-runner.js +62 -0
  52. package/src/transform.js +765 -0
@@ -0,0 +1,793 @@
1
+ import { TypeDefError } from "../external/classErrors.js"
2
+ import { tokenize } from "../lexer.js"
3
+
4
+ const LEADING_STATEMENT_KEYWORDS = new Set([
5
+ "return", "throw", "yield", "case", "do", "else",
6
+ "in", "of", "instanceof"
7
+ ])
8
+
9
+ function extractExpr(str, startPos) {
10
+ let depth = 0
11
+ let i = startPos
12
+
13
+ while (i < str.length) {
14
+ const ch = str[i]
15
+
16
+ if (ch === '"' || ch === "'" || ch === "`") {
17
+ const quote = ch
18
+ i++
19
+ while (i < str.length) {
20
+ if (str[i] === "\\") { i += 2; continue }
21
+ if (str[i] === quote) { i++; break }
22
+ i++
23
+ }
24
+ continue
25
+ }
26
+
27
+ if (ch === "(" || ch === "[" || ch === "{") {
28
+ depth++
29
+ i++
30
+ continue
31
+ }
32
+ if (ch === ")" || ch === "]" || ch === "}") {
33
+ if (depth === 0) break
34
+ depth--
35
+ i++
36
+ continue
37
+ }
38
+
39
+ if (depth === 0) {
40
+ const two = str.slice(i, i + 2)
41
+ if (["==", "!=", ">=", "<=", "&&", "||", "??"].includes(two)) break
42
+ if (["+", "-", "*", "/", "%", "<", ">", "?", ":", ";", ",", "\n"].includes(ch)) break
43
+ }
44
+
45
+ i++
46
+ }
47
+
48
+ return str.slice(startPos, i).trim()
49
+ }
50
+
51
+ function extractExprRaw(str, startPos) {
52
+ let i = startPos
53
+ while (i < str.length && (str[i] === ' ' || str[i] === '\t')) i++
54
+ const contentStart = i
55
+
56
+ let depth = 0
57
+ let ternaryDepth = 0
58
+
59
+ while (i < str.length) {
60
+ const ch = str[i]
61
+ const two = str.slice(i, i + 2)
62
+
63
+ if (ch === '"' || ch === "'" || ch === '`') {
64
+ const quote = ch
65
+ i++
66
+ while (i < str.length) {
67
+ if (str[i] === '\\') { i += 2; continue }
68
+
69
+ if (quote === '`' && str[i] === '$' && str[i + 1] === '{') {
70
+ i += 2
71
+ let interpDepth = 1
72
+ while (i < str.length && interpDepth > 0) {
73
+ const c = str[i]
74
+ if (c === '\\') { i += 2; continue }
75
+
76
+ if (c === '"' || c === "'" || c === '`') {
77
+ const innerQuote = c
78
+ i++
79
+ while (i < str.length) {
80
+ if (str[i] === '\\') { i += 2; continue }
81
+ if (str[i] === innerQuote) { i++; break }
82
+ i++
83
+ }
84
+ continue
85
+ }
86
+
87
+ if (c === '{') { interpDepth++; i++; continue }
88
+ if (c === '}') { interpDepth--; i++; continue }
89
+ i++
90
+ }
91
+ continue
92
+ }
93
+
94
+ if (str[i] === quote) { i++; break }
95
+ i++
96
+ }
97
+ continue
98
+ }
99
+
100
+ if (ch === '(' || ch === '[' || ch === '{') { depth++; i++; continue }
101
+
102
+ if (ch === ')' || ch === ']' || ch === '}') {
103
+ if (depth === 0) break
104
+ depth--; i++; continue
105
+ }
106
+
107
+ if (depth === 0) {
108
+ if (two === '=>') { i += 2; continue }
109
+
110
+ if (['==', '!=', '>=', '<=', '&&', '||', '??',
111
+ '+=', '-=', '*=', '/=', '**'].includes(two)) {
112
+ i += 2; continue
113
+ }
114
+
115
+ if ((ch === '-' || ch === '+') && i === contentStart) { i++; continue }
116
+
117
+ if ([';', ',', '\n'].includes(ch)) break
118
+
119
+ if (ch === '?') { ternaryDepth++; i++; continue }
120
+
121
+ if (ch === ':') {
122
+ if (ternaryDepth > 0) { ternaryDepth--; i++; continue }
123
+ break
124
+ }
125
+ }
126
+
127
+ i++
128
+ }
129
+
130
+ return {
131
+ expr: str.slice(contentStart, i).trim(),
132
+ start: contentStart,
133
+ end: i
134
+ }
135
+ }
136
+
137
+ function replaceOperator(code, keyword, fn) {
138
+ let result = ""
139
+ let i = 0
140
+
141
+ while (i < code.length) {
142
+ const slice = code.slice(i)
143
+ const match = slice.match(new RegExp(`^${keyword}\\s+`))
144
+
145
+ if (match) {
146
+ const afterKeyword = i + match[0].length
147
+ const expr = extractExpr(code, afterKeyword)
148
+ result += `${fn}(${expr})`
149
+ i = afterKeyword + expr.length
150
+ continue
151
+ }
152
+
153
+ result += code[i]
154
+ i++
155
+ }
156
+
157
+ return result
158
+ }
159
+
160
+ // Read balanced type annotations, including multiline unions.
161
+ function readTypeAnnotation(src, pos) {
162
+ let i = pos
163
+
164
+ const skipSpace = acrossLines => {
165
+ while (i < src.length && (src[i] === " " || src[i] === "\t" || src[i] === "\r" ||
166
+ (acrossLines && src[i] === "\n"))) i++
167
+ }
168
+
169
+ const readGroup = (open, close) => {
170
+ let depth = 0
171
+ while (i < src.length) {
172
+ if (src[i] === "\n") return false
173
+ if (src[i] === open) depth++
174
+ else if (src[i] === close) {
175
+ depth--
176
+ if (depth === 0) { i++; return true }
177
+ }
178
+ i++
179
+ }
180
+ return false
181
+ }
182
+
183
+ const readAtom = () => {
184
+ skipSpace(false)
185
+
186
+ if (src[i] === "[") {
187
+ if (!readGroup("[", "]")) return false
188
+ } else {
189
+ if (!/[A-Za-z_$]/.test(src[i] ?? "")) return false
190
+ while (i < src.length && /[\w$]/.test(src[i])) i++
191
+
192
+ if (src[i] === ":" && src[i + 1] === ":") {
193
+ i += 2
194
+ while (i < src.length && /[\w$]/.test(src[i])) i++
195
+ }
196
+ if (src[i] === "<" && !readGroup("<", ">")) return false
197
+ }
198
+
199
+ while (src[i] === "[" && src[i + 1] === "]") i += 2
200
+ return true
201
+ }
202
+
203
+ if (!readAtom()) return null
204
+
205
+ for (;;) {
206
+ const resume = i
207
+ skipSpace(true)
208
+
209
+ const separator = src[i]
210
+ if ((separator !== "|" && separator !== "&") || src[i + 1] === separator) {
211
+ i = resume
212
+ break
213
+ }
214
+
215
+ i++
216
+ if (!readAtom()) { i = resume; break }
217
+ }
218
+
219
+ if (src[i] === "?") i++
220
+
221
+ const type = src.slice(pos, i).trim().replace(/\s+/g, " ")
222
+ return type ? { type, end: i } : null
223
+ }
224
+
225
+ // Split parameters only at top-level commas.
226
+ function splitArguments(argsStr) {
227
+ const args = []
228
+ let depth = 0
229
+ let current = ""
230
+ const isWord = c => !!c && /[A-Za-z0-9_$]/.test(c)
231
+
232
+ for (let i = 0; i < argsStr.length; i++) {
233
+ const ch = argsStr[i]
234
+
235
+ if (ch === '"' || ch === "'" || ch === "`") {
236
+ current += ch
237
+ i++
238
+ while (i < argsStr.length) {
239
+ if (argsStr[i] === "\\") {
240
+ current += argsStr[i]
241
+ i++
242
+ if (i < argsStr.length) { current += argsStr[i]; i++ }
243
+ continue
244
+ }
245
+ current += argsStr[i]
246
+ if (argsStr[i] === ch) { i++; break }
247
+ i++
248
+ }
249
+ i--
250
+ continue
251
+ }
252
+
253
+ if (ch === "(" || ch === "[" || ch === "{") { depth++; current += ch; continue }
254
+ if (ch === ")" || ch === "]" || ch === "}") { depth--; current += ch; continue }
255
+ if (ch === "<" && isWord(argsStr[i - 1]) && argsStr[i + 1] !== "=" && argsStr[i + 1] !== "<") {
256
+ depth++; current += ch; continue
257
+ }
258
+ if (ch === ">" && depth > 0 && argsStr[i - 1] !== "=" && argsStr[i + 1] !== "=") {
259
+ depth--; current += ch; continue
260
+ }
261
+ if (ch === "," && depth === 0) {
262
+ args.push(current.trim())
263
+ current = ""
264
+ continue
265
+ }
266
+ current += ch
267
+ }
268
+ if (current.trim()) args.push(current.trim())
269
+
270
+ return args
271
+ }
272
+
273
+ const ARGUMENT_NAME = /^([$A-Za-z_][$\w]*)(\?)?\s*/
274
+
275
+ function parseTypedArgs(argsStr) {
276
+ return splitArguments(argsStr).map(arg => {
277
+ const untyped = { raw: arg, name: arg, type: null, optional: false, default: null }
278
+
279
+ const head = ARGUMENT_NAME.exec(arg)
280
+ if (!head) return untyped
281
+
282
+ let i = head[0].length
283
+ let type = null
284
+
285
+ if (arg[i] === ":") {
286
+ const annotation = readTypeAnnotation(arg, i + 1)
287
+ if (!annotation) return untyped
288
+ type = annotation.type
289
+ i = annotation.end
290
+ }
291
+
292
+ while (i < arg.length && /\s/.test(arg[i])) i++
293
+
294
+ if (i < arg.length && arg[i] !== "=") return untyped
295
+ const def = arg[i] === "=" ? arg.slice(i + 1).trim() : null
296
+
297
+ return { raw: arg, name: head[1], type, optional: !!head[2], default: def || null }
298
+ })
299
+ }
300
+
301
+ function inferDefaultType(def) {
302
+ const trimmed = def.trim()
303
+
304
+ if (/^-?\d+$/.test(trimmed)) return "int"
305
+ if (/^-?\d+\.\d+$/.test(trimmed)) return "float"
306
+ if (trimmed === "true" || trimmed === "false") return "bool"
307
+ if (/^(["'`])[\s\S]*\1$/.test(trimmed)) return "string"
308
+
309
+ return null
310
+ }
311
+
312
+ function buildTypedArgsResult(parsedArgs, fnName) {
313
+ const signature = parsedArgs.map(a => {
314
+ if (a.default !== null) return `${a.name} = ${a.default}`
315
+ return a.name
316
+ }).join(", ")
317
+
318
+ const checks = parsedArgs
319
+ .filter(a => a.type && a.type !== "any")
320
+ .map((a, i) => {
321
+ const expected = a.type.split("|").map(t => t.trim()).join(" or ")
322
+ const message = a.optional
323
+ ? `${fnName}: argument "${a.name}" expected ${expected}`
324
+ : `function "${fnName}": argument<${i}> "${a.name}" expected ${expected}`
325
+
326
+ return `__typed_parameter__(${a.name}, "${a.type}", "${a.name}", ${a.optional}, \`${message}, got \${type(${a.name})}\`)`
327
+ })
328
+ .join("\n ")
329
+
330
+ return { signature, checks }
331
+ }
332
+
333
+ let __isInsideStringSrc = null
334
+ let __isInsideStringTokens = null
335
+
336
+ function isInsideString(src, index) {
337
+ if (src !== __isInsideStringSrc) {
338
+ __isInsideStringSrc = src
339
+ __isInsideStringTokens = tokenize(src)
340
+ }
341
+
342
+ const tokens = __isInsideStringTokens
343
+ let lo = 0
344
+ let hi = tokens.length - 1
345
+
346
+ while (lo <= hi) {
347
+ const mid = (lo + hi) >> 1
348
+ const token = tokens[mid]
349
+ if (index < token.start) hi = mid - 1
350
+ else if (index >= token.end) lo = mid + 1
351
+ else return token.type === "string" || token.type === "template" || token.type === "regex" || token.type === "comment"
352
+ }
353
+
354
+ return false
355
+ }
356
+
357
+ function extractExprBackward(str, endPosExclusive) {
358
+ let i = endPosExclusive
359
+ while (i > 0 && /\s/.test(str[i - 1])) i--
360
+ const contentEnd = i
361
+
362
+ let depth = 0
363
+
364
+ while (i > 0) {
365
+ const ch = str[i - 1]
366
+
367
+ if (ch === '"' || ch === "'" || ch === "`") break
368
+
369
+ if (ch === ")" || ch === "]" || ch === "}") { depth++; i--; continue }
370
+ if (ch === "(" || ch === "[" || ch === "{") {
371
+ if (depth === 0) break
372
+ depth--; i--; continue
373
+ }
374
+
375
+ if (depth === 0) {
376
+ const two = str.slice(Math.max(0, i - 2), i)
377
+ if (["==", "!=", ">=", "<=", "&&", "||", "??", "=>"].includes(two)) break
378
+ if (["+", "-", "*", "/", "%", "<", ">", "=", "?", ":", ";", ",", "\n"].includes(ch)) break
379
+ }
380
+
381
+ i--
382
+ }
383
+
384
+ let start = i
385
+ while (start < contentEnd && /\s/.test(str[start])) start++
386
+
387
+ for (;;) {
388
+ const m = str.slice(start, contentEnd).match(/^([A-Za-z$_][\w$]*)\s+/)
389
+ if (!m || !LEADING_STATEMENT_KEYWORDS.has(m[1])) break
390
+ start += m[0].length
391
+ }
392
+
393
+ return { expr: str.slice(start, contentEnd).trim(), start }
394
+ }
395
+
396
+ function extractExprForward(str, startPos) {
397
+ let depth = 0
398
+ let i = startPos
399
+
400
+ while (i < str.length) {
401
+ const ch = str[i]
402
+
403
+ if (ch === '"' || ch === "'" || ch === "`") {
404
+ const quote = ch
405
+ i++
406
+ while (i < str.length) {
407
+ if (str[i] === "\\") { i += 2; continue }
408
+ if (str[i] === quote) { i++; break }
409
+ i++
410
+ }
411
+ continue
412
+ }
413
+
414
+ if (ch === "(" || ch === "[" || ch === "{") { depth++; i++; continue }
415
+ if (ch === ")" || ch === "]" || ch === "}") {
416
+ if (depth === 0) break
417
+ depth--; i++; continue
418
+ }
419
+
420
+ if (depth === 0) {
421
+ const two = str.slice(i, i + 2)
422
+ if (["==", "!=", ">=", "<=", "&&", "||", "??"].includes(two)) break
423
+ if (["+", "-", "*", "/", "%", "<", ">", "?", ":", ";", ",", "\n"].includes(ch)) break
424
+ }
425
+
426
+ i++
427
+ }
428
+
429
+ return { expr: str.slice(startPos, i).trim(), end: i }
430
+ }
431
+
432
+ function replaceBinaryOperator(code, token, fn) {
433
+ let result = code
434
+ let searchFrom = result.length
435
+
436
+ while (searchFrom >= 0) {
437
+ const idx = result.lastIndexOf(token, searchFrom)
438
+ if (idx === -1) break
439
+ searchFrom = idx - 1
440
+
441
+ if (isInsideString(result, idx)) continue
442
+
443
+ const { expr: left, start: leftStart } = extractExprBackward(result, idx)
444
+ const { expr: right, end: rightEnd } = extractExprForward(result, idx + token.length)
445
+
446
+ if (!left || !right) continue
447
+
448
+ result = result.slice(0, leftStart) + `${fn}(${left}, ${right})` + result.slice(rightEnd)
449
+ }
450
+
451
+ return result
452
+ }
453
+
454
+ function readTypeExtends(code, i) {
455
+ while (/\s/.test(code[i])) i++;
456
+
457
+ if (!code.startsWith("extends", i)) {
458
+ return {
459
+ end: i,
460
+ extends: null
461
+ };
462
+ }
463
+
464
+ i += "extends".length;
465
+
466
+ while (/\s/.test(code[i])) i++;
467
+
468
+ const start = i;
469
+
470
+ while (/[A-Za-z0-9_$]/.test(code[i])) i++;
471
+
472
+ return {
473
+ end: i,
474
+ extends: code.slice(start, i)
475
+ };
476
+ }
477
+
478
+ function parseTypesEdits(code) {
479
+ const edits = [];
480
+ let i = 0;
481
+ const isIdentifierPart = char => !!char && /[A-Za-z0-9_$]/.test(char)
482
+
483
+ while (i < code.length) {
484
+ if (
485
+ !code.startsWith("type", i) ||
486
+ isIdentifierPart(code[i - 1]) ||
487
+ isIdentifierPart(code[i + 4])
488
+ ) {
489
+ i++;
490
+ continue;
491
+ }
492
+
493
+ const start = i;
494
+ i += 4;
495
+
496
+ while (/\s/.test(code[i])) i++;
497
+
498
+ const nameStart = i;
499
+ while (isIdentifierPart(code[i])) i++;
500
+
501
+ const typeName = code.slice(nameStart, i);
502
+
503
+ if (!typeName) {
504
+ i = start + 1;
505
+ continue;
506
+ }
507
+
508
+ while (/\s/.test(code[i])) i++;
509
+
510
+ if (code[i] === "=") {
511
+ i++;
512
+
513
+ let { expr, end } = extractExprForward(code, i);
514
+
515
+ const finalArgs = {}
516
+
517
+ if(expr.startsWith("typeof")) expr = expr.split("typeof")[1].trim()
518
+ if(expr.startsWith("extends")) {
519
+ const extendsObj = expr.split("extends")[1]
520
+
521
+ finalArgs["extends"] = extendsObj.trim()
522
+ expr = `"${extendsObj.trim()}"`
523
+ }
524
+
525
+ finalArgs["type"] = "one-line-expr"
526
+
527
+ edits.push({
528
+ start,
529
+ end,
530
+ replacement: `const ${typeName} = __type_def__("${typeName}", ${expr}, ${Object.keys(finalArgs).length > 0 ? JSON.stringify(finalArgs) : ""})`
531
+ });
532
+
533
+ i = end;
534
+ continue;
535
+ }
536
+
537
+ if (code[i] === "(") {
538
+ const args = readBalanced(code, i, "(", ")");
539
+ i = args.end;
540
+
541
+ const ext = readTypeExtends(code, i);
542
+ i = ext.end;
543
+
544
+ const finalArgs = {}
545
+
546
+ if(ext.extends) {
547
+ finalArgs["extends"] = ext.extends
548
+ }
549
+
550
+ while (/\s/.test(code[i])) i++;
551
+
552
+ const body = readBalanced(code, i, "{", "}");
553
+ i = body.end;
554
+
555
+ let bodyContent = body.content.trim()
556
+
557
+ const normalizedBody = bodyContent.replace(/;\s*$/, "").trim()
558
+ if (!/^return(?:\s+[\s\S]+)?$/.test(normalizedBody)) {
559
+ throw new TypeDefError(`The "${typeName}" type body must contain exactly one return statement`)
560
+ }
561
+
562
+ if (normalizedBody === "return") bodyContent = "return true"
563
+
564
+ edits.push({
565
+ start,
566
+ end: i,
567
+ replacement: `const ${typeName} = __type_def__("${typeName}", (${args.content}) => {${bodyContent}}, ${Object.keys(finalArgs).length > 0 ? JSON.stringify(finalArgs) : "{}"})`
568
+ });
569
+
570
+ continue;
571
+ }
572
+
573
+ i = start + 1;
574
+ }
575
+
576
+ return edits;
577
+ }
578
+
579
+ function applyStringEdits(code, edits) {
580
+ let out = "";
581
+ let cursor = 0;
582
+ for (const { start, end, replacement } of edits) {
583
+ out += code.slice(cursor, start) + replacement;
584
+ cursor = end;
585
+ }
586
+ return out + code.slice(cursor);
587
+ }
588
+
589
+ function parseTypes(code) {
590
+ return applyStringEdits(code, parseTypesEdits(code));
591
+ }
592
+
593
+ function readBalanced(code, start, open, close) {
594
+ let depth = 0;
595
+ let i = start;
596
+
597
+ while (i < code.length) {
598
+ const ch = code[i];
599
+
600
+ if (ch === '"' || ch === "'" || ch === "`") {
601
+ const quote = ch;
602
+ i++;
603
+
604
+ while (i < code.length) {
605
+ if (code[i] === "\\") {
606
+ i += 2;
607
+ continue;
608
+ }
609
+
610
+ if (code[i] === quote) {
611
+ break;
612
+ }
613
+
614
+ i++;
615
+ }
616
+ }
617
+
618
+ if (code[i] === open) depth++;
619
+ if (code[i] === close) depth--;
620
+
621
+ i++;
622
+ if (depth === 0) break
623
+ }
624
+
625
+ if (depth !== 0) {
626
+ throw new TypeDefError(`Unclosed "${open}" in type declaration`)
627
+ }
628
+
629
+ return {
630
+ content: code.slice(start + 1, i - 1),
631
+ end: i
632
+ };
633
+ }
634
+
635
+ function replaceCondOperator(code, operator, replacement) {
636
+ let out = ""
637
+ let state = "code"
638
+ let depth = 0
639
+
640
+ const isWord = c => c && /[A-Za-z0-9_$]/.test(c)
641
+
642
+ for (let i = 0; i < code.length; i++) {
643
+ const c = code[i]
644
+ const n = code[i + 1]
645
+
646
+ if (state === "code") {
647
+ if (c === "'") {
648
+ state = "single"
649
+ out += c
650
+ continue
651
+ }
652
+
653
+ if (c === '"') {
654
+ state = "double"
655
+ out += c
656
+ continue
657
+ }
658
+
659
+ if (c === "`") {
660
+ state = "template"
661
+ out += c
662
+ continue
663
+ }
664
+
665
+ if (c === "/" && n === "/") {
666
+ state = "lineComment"
667
+ out += "//"
668
+ i++
669
+ continue
670
+ }
671
+
672
+ if (c === "/" && n === "*") {
673
+ state = "blockComment"
674
+ out += "/*"
675
+ i++
676
+ continue
677
+ }
678
+
679
+ if (
680
+ code.startsWith(operator, i) &&
681
+ !isWord(code[i - 1]) &&
682
+ !isWord(code[i + operator.length])
683
+ ) {
684
+ out += replacement
685
+ i += operator.length - 1
686
+ continue
687
+ }
688
+
689
+ out += c
690
+ continue
691
+ }
692
+
693
+ if (state === "single") {
694
+ out += c
695
+ if (c === "\\" && n) {
696
+ out += n
697
+ i++
698
+ } else if (c === "'") {
699
+ state = "code"
700
+ }
701
+ continue
702
+ }
703
+
704
+ if (state === "double") {
705
+ out += c
706
+ if (c === "\\" && n) {
707
+ out += n
708
+ i++
709
+ } else if (c === '"') {
710
+ state = "code"
711
+ }
712
+ continue
713
+ }
714
+
715
+ if (state === "template") {
716
+ if (c === "$" && n === "{") {
717
+ state = "templateExpr"
718
+ depth = 1
719
+ out += "${"
720
+ i++
721
+ continue
722
+ }
723
+
724
+ out += c
725
+
726
+ if (c === "\\" && n) {
727
+ out += n
728
+ i++
729
+ } else if (c === "`") {
730
+ state = "code"
731
+ }
732
+
733
+ continue
734
+ }
735
+
736
+ if (state === "templateExpr") {
737
+ if (c === "{") depth++
738
+ if (c === "}") depth--
739
+
740
+ if (
741
+ code.startsWith(operator, i) &&
742
+ !isWord(code[i - 1]) &&
743
+ !isWord(code[i + operator.length])
744
+ ) {
745
+ out += replacement
746
+ i += operator.length - 1
747
+ continue
748
+ }
749
+
750
+ out += c
751
+
752
+ if (depth === 0)
753
+ state = "template"
754
+
755
+ continue
756
+ }
757
+
758
+ if (state === "lineComment") {
759
+ out += c
760
+ if (c === "\n")
761
+ state = "code"
762
+ continue
763
+ }
764
+
765
+ if (state === "blockComment") {
766
+ out += c
767
+ if (c === "*" && n === "/") {
768
+ out += "/"
769
+ i++
770
+ state = "code"
771
+ }
772
+ }
773
+ }
774
+
775
+ return out
776
+ }
777
+
778
+ export {
779
+ extractExpr,
780
+ extractExprRaw,
781
+ extractExprBackward,
782
+ replaceBinaryOperator,
783
+ replaceOperator,
784
+ parseTypedArgs,
785
+ readTypeAnnotation,
786
+ buildTypedArgsResult,
787
+ inferDefaultType,
788
+ isInsideString,
789
+ parseTypes,
790
+ parseTypesEdits,
791
+ readBalanced,
792
+ replaceCondOperator
793
+ }