• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stackus / goht / 14768173832

01 May 2025 02:03AM UTC coverage: 79.722% (+0.2%) from 79.532%
14768173832

push

github

stackus
update documentation

2693 of 3378 relevant lines covered (79.72%)

0.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.81
/compiler/lexers_haml.go
1
package compiler
2

3
import (
4
        "slices"
5
        "strings"
6
        "text/scanner"
7
)
8

9
func lexHamlLineStart(l *lexer) lexFn {
1✔
10
        switch l.peek() {
1✔
11
        case '}':
1✔
12
                l.emit(tTemplateEnd)
1✔
13
                l.skip()
1✔
14
                return lexGoLineStart
1✔
15
        case scanner.EOF:
1✔
16
                l.emit(tEOF)
1✔
17
                return nil
1✔
18
        case '\n', '\r':
×
19
                return lexHamlLineEnd
×
20
        default:
1✔
21
                return lexHamlIndent
1✔
22
        }
23
}
24

25
func lexHamlIndent(l *lexer) lexFn {
1✔
26
        // accept spaces and tabs so that we can report about improper indentation
1✔
27
        l.acceptRun(" \t")
1✔
28
        indent := l.current()
1✔
29

1✔
30
        // there has not been any indentation yet
1✔
31
        if l.indent == 0 && len(indent) == 0 {
1✔
32
                // return an error that indents are required
×
33
                return l.errorf("haml templates must be indented")
×
34
        }
×
35

36
        // validate the indent against the sequence and char
37
        if lexHamlErr := l.validateIndent(indent); lexHamlErr != nil {
2✔
38
                return lexHamlErr
1✔
39
        }
1✔
40

41
        l.indent = len(l.current()) // useful for parsing filters
1✔
42
        l.emit(tIndent)
1✔
43
        return lexHamlContentStart
1✔
44
}
45

46
func lexHamlContentStart(l *lexer) lexFn {
1✔
47
        switch l.peek() {
1✔
48
        case '%':
1✔
49
                return lexHamlTag
1✔
50
        case '#':
1✔
51
                return lexHamlId
1✔
52
        case '.':
1✔
53
                return lexHamlClass
1✔
54
        case '\\':
1✔
55
                l.skip()
1✔
56
                return lexHamlTextStart
1✔
57
        case '!':
1✔
58
                if s := l.peekAhead(3); s == "!!!" {
2✔
59
                        // TODO return an error if we're nesting doctypes
1✔
60
                        return lexHamlDoctype
1✔
61
                }
1✔
62
                return lexHamlUnescaped
1✔
63
        case '-':
1✔
64
                return lexHamlSilentScript
1✔
65
        case '=':
1✔
66
                return lexHamlOutputCode
1✔
67
        case '/':
1✔
68
                return lexHamlComment
1✔
69
        case ':':
1✔
70
                return lexHamlFilterStart
1✔
71
        case '{':
1✔
72
                return lexHamlAttributesStart
1✔
73
        case scanner.EOF, '\n', '\r':
×
74
                return lexHamlLineEnd
×
75
        default:
1✔
76
                return lexHamlTextStart
1✔
77
        }
78
}
79

80
func lexHamlContent(l *lexer) lexFn {
1✔
81
        switch l.peek() {
1✔
82
        case '#':
1✔
83
                return lexHamlId
1✔
84
        case '.':
1✔
85
                return lexHamlClass
1✔
86
        case '[':
1✔
87
                return lexHamlObjectReference
1✔
88
        case '{':
1✔
89
                return lexHamlAttributesStart
1✔
90
        case '!':
1✔
91
                return lexHamlUnescaped
1✔
92
        case '=':
1✔
93
                return lexHamlOutputCode
1✔
94
        case '/':
1✔
95
                return lexHamlVoidTag
1✔
96
        case '>', '<':
1✔
97
                return lexHamlWhitespaceRemoval
1✔
98
        case scanner.EOF, '\n', '\r':
1✔
99
                return lexHamlLineEnd
1✔
100
        default:
1✔
101
                return lexHamlTextStart
1✔
102
        }
103
}
104

105
func lexHamlContentEnd(l *lexer) lexFn {
1✔
106
        switch l.peek() {
1✔
107
        case '=':
×
108
                return lexHamlOutputCode
×
109
        case '/':
×
110
                return lexHamlVoidTag
×
111
        case '>', '<':
1✔
112
                return lexHamlWhitespaceRemoval
1✔
113
        case scanner.EOF, '\n', '\r':
1✔
114
                return lexHamlLineEnd
1✔
115
        default:
×
116
                return lexHamlTextStart
×
117
        }
118
}
119

120
func lexHamlLineEnd(l *lexer) lexFn {
1✔
121
        l.skipRun(" \t")
1✔
122

1✔
123
        switch l.peek() {
1✔
124
        case '\n', '\r':
1✔
125
                return lexHamlNewLine
1✔
126
        case scanner.EOF:
1✔
127
                l.emit(tEOF)
1✔
128
                return nil
1✔
129
        default:
×
130
                return l.errorf("unexpected character: %q", l.peek())
×
131
        }
132
}
133

134
func lexHamlNewLine(l *lexer) lexFn {
1✔
135
        l.acceptRun("\n\r")
1✔
136
        l.emit(tNewLine)
1✔
137
        return lexHamlLineStart
1✔
138
}
1✔
139

140
func hamlIdentifier(typ tokenType, l *lexer) lexFn {
1✔
141
        l.skip() // eat symbol
1✔
142

1✔
143
        // these characters may follow an identifier
1✔
144
        const mayFollowIdentifier = "%#.[{=!/<> \t\n\r"
1✔
145

1✔
146
        l.acceptUntil(mayFollowIdentifier)
1✔
147
        if l.current() == "" {
2✔
148
                return l.errorf("%s identifier expected", typ)
1✔
149
        }
1✔
150
        l.emit(typ)
1✔
151
        return lexHamlContent
1✔
152
}
153

154
func lexHamlTag(l *lexer) lexFn {
1✔
155
        return hamlIdentifier(tTag, l)
1✔
156
}
1✔
157

158
func lexHamlId(l *lexer) lexFn {
1✔
159
        return hamlIdentifier(tId, l)
1✔
160
}
1✔
161

162
func lexHamlClass(l *lexer) lexFn {
1✔
163
        return hamlIdentifier(tClass, l)
1✔
164
}
1✔
165

166
func lexHamlObjectReference(l *lexer) lexFn {
1✔
167
        l.skip() // eat opening bracket
1✔
168
        r := continueToMatchingBrace(l, ']', false)
1✔
169
        if r == scanner.EOF {
1✔
170
                return l.errorf("object reference not closed: eof")
×
171
        }
×
172
        l.backup()
1✔
173
        l.emit(tObjectRef)
1✔
174
        l.skip() // skip closing bracket
1✔
175
        return lexHamlContent
1✔
176
}
177

178
func lexHamlAttributesStart(l *lexer) lexFn {
1✔
179
        l.skip()
1✔
180
        return lexHamlAttribute
1✔
181
}
1✔
182

183
func lexHamlAttributesEnd(l *lexer) lexFn {
1✔
184
        l.skip()
1✔
185
        return lexHamlContent
1✔
186
}
1✔
187

188
func lexHamlAttribute(l *lexer) lexFn {
1✔
189
        // supported attributes
1✔
190
        // key
1✔
191
        // key:value
1✔
192
        // key?value
1✔
193
        // @attributes: []any (string, map[string]string, map[string]bool)
1✔
194

1✔
195
        l.skipRun(", \t\n\r")
1✔
196

1✔
197
        switch l.peek() {
1✔
198
        case '}':
1✔
199
                return lexHamlAttributesEnd
1✔
200
        case '@':
1✔
201
                return lexHamlAttributeCommandStart
1✔
202
        default:
1✔
203
                return lexHamlAttributeName
1✔
204
        }
205
}
206

207
func lexHamlAttributeName(l *lexer) lexFn {
1✔
208
        if l.peek() == '"' || l.peek() == '`' {
2✔
209
                r := continueToMatchingQuote(l, tAttrName, false)
1✔
210
                if r == scanner.EOF {
1✔
211
                        return l.errorf("attribute name not closed: eof")
×
212
                } else if r != '"' && r != '`' {
1✔
213
                        return l.errorf("unexpected character: %q", r)
×
214
                }
×
215
        } else {
1✔
216
                l.acceptUntil("?:,}{\" \t\n\r")
1✔
217
                if l.current() == "" {
1✔
218
                        return l.errorf("attribute name expected")
×
219
                }
×
220
                l.emit(tAttrName)
1✔
221
        }
222

223
        l.skipRun(" \t\n\r")
1✔
224
        switch l.peek() {
1✔
225
        case '?', ':':
1✔
226
                return lexHamlAttributeOperator
1✔
227
        case ',', '}':
1✔
228
                return lexHamlAttributeEnd
1✔
229
        default:
1✔
230
                return l.errorf("unexpected character: %q", l.peek())
1✔
231
        }
232
}
233

234
func lexHamlAttributeOperator(l *lexer) lexFn {
1✔
235
        l.skipRun(" \t\n\r")
1✔
236
        switch l.peek() {
1✔
237
        case '?', ':':
1✔
238
                l.next()
1✔
239
                l.emit(tAttrOperator)
1✔
240
                return lexHamlAttributeValue
1✔
241
        }
242
        return l.errorf("unexpected character: %q", l.peek())
×
243
}
244

245
func lexHamlAttributeValue(l *lexer) lexFn {
1✔
246
        l.skipRun(" \t\n\r")
1✔
247

1✔
248
        switch l.peek() {
1✔
249
        case '"', '`':
1✔
250
                return lexHamlAttributeStaticValue
1✔
251
        case '#':
1✔
252
                return lexHamlAttributeDynamicValue
1✔
253
        }
254
        return l.errorf("unexpected character: %q", l.peek())
×
255
}
256

257
func lexHamlAttributeStaticValue(l *lexer) lexFn {
1✔
258
        r := continueToMatchingQuote(l, tAttrEscapedValue, true)
1✔
259
        if r == scanner.EOF {
1✔
260
                return l.errorf("attribute value not closed: eof")
×
261
        } else if r != '"' && r != '`' {
1✔
262
                return l.errorf("unexpected character: %q", r)
×
263
        }
×
264
        return lexHamlAttributeEnd
1✔
265
}
266

267
func lexHamlAttributeDynamicValue(l *lexer) lexFn {
1✔
268
        l.skip() // skip hash
1✔
269
        if l.peek() != '{' {
1✔
270
                return l.errorf("unexpected character: %q", l.peek())
×
271
        }
×
272
        l.skip() // skip opening brace
1✔
273
        r := continueToMatchingBrace(l, '}', false)
1✔
274
        if r == scanner.EOF {
1✔
275
                return l.errorf("attribute value not closed: eof")
×
276
        }
×
277
        l.backup()
1✔
278
        l.emit(tAttrDynamicValue)
1✔
279
        l.skip() // skip closing brace
1✔
280
        return lexHamlAttributeEnd
1✔
281
}
282

283
func lexHamlAttributeCommandStart(l *lexer) lexFn {
1✔
284
        l.skipRun("@")
1✔
285
        l.acceptUntil(": \t\n\r")
1✔
286
        if l.current() == "" {
1✔
287
                return l.errorf("command code expected")
×
288
        }
×
289
        switch l.current() {
1✔
290
        case "attributes":
1✔
291
                return lexHamlAttributeCommand(tAttributesCommand)
1✔
292
        default:
×
293
                return l.errorf("unknown attribute command: %s", l.current())
×
294
        }
295
}
296

297
func lexHamlAttributeCommand(command tokenType) lexFn {
1✔
298
        return func(l *lexer) lexFn {
2✔
299
                l.ignore()
1✔
300
                l.skipUntil(":")
1✔
301
                l.skipUntil("{")
1✔
302
                l.skip() // skip opening brace
1✔
303
                r := continueToMatchingBrace(l, '}', true)
1✔
304
                if r == scanner.EOF {
1✔
305
                        return l.errorf("attribute value not closed: eof")
×
306
                }
×
307
                l.backup()
1✔
308
                l.emit(command)
1✔
309
                l.skip() // skip closing brace
1✔
310

1✔
311
                return lexHamlAttributeEnd
1✔
312
        }
313
}
314

315
func lexHamlAttributeEnd(l *lexer) lexFn {
1✔
316
        l.skipRun(" \t\n\r")
1✔
317
        switch l.peek() {
1✔
318
        case ',':
1✔
319
                l.skip()
1✔
320
                return lexHamlAttribute
1✔
321
        case '}':
1✔
322
                return lexHamlAttributesEnd
1✔
323
        default:
1✔
324
                return l.errorf("unexpected character: %c", l.peek())
1✔
325
        }
326
}
327

328
func lexHamlWhitespaceRemoval(l *lexer) lexFn {
1✔
329
        direction := l.skip()
1✔
330
        switch direction {
1✔
331
        case '>':
1✔
332
                l.emit(tNukeOuterWhitespace)
1✔
333
        case '<':
1✔
334
                l.emit(tNukeInnerWhitespace)
1✔
335
        default:
×
336
                return l.errorf("unexpected character: %q", direction)
×
337
        }
338
        return lexHamlContentEnd
1✔
339
}
340

341
func lexHamlTextStart(l *lexer) lexFn {
1✔
342
        l.skipRun(" \t")
1✔
343
        return lexHamlTextContent
1✔
344
}
1✔
345

346
func lexHamlTextContent(l *lexer) lexFn {
1✔
347
        l.acceptUntil("\\#\n\r")
1✔
348
        switch l.peek() {
1✔
349
        case '\\':
1✔
350
                isHashComing := l.peekAhead(2)
1✔
351
                if isHashComing == "\\#" {
2✔
352
                        l.skip()
1✔
353
                        // was the backslash being escaped?
1✔
354
                        if !strings.HasSuffix(l.current(), "\\") {
2✔
355
                                l.next()
1✔
356
                        }
1✔
357
                } else {
1✔
358
                        l.next()
1✔
359
                }
1✔
360
                return lexHamlTextContent
1✔
361
        case '#':
1✔
362
                return lexHamlDynamicText
1✔
363
        default:
1✔
364
                if l.current() != "" {
2✔
365
                        l.emit(tPlainText)
1✔
366
                }
1✔
367
                return lexHamlLineEnd
1✔
368
        }
369
}
370

371
func lexHamlDynamicText(l *lexer) lexFn {
1✔
372
        if s := l.peekAhead(2); s != "#{" {
2✔
373
                l.next()
1✔
374
                return lexHamlTextContent
1✔
375
        }
1✔
376
        if l.current() != "" {
2✔
377
                l.emit(tPlainText)
1✔
378
        }
1✔
379
        l.skipRun("#{")
1✔
380
        r := continueToMatchingBrace(l, '}', false)
1✔
381
        if r == scanner.EOF {
2✔
382
                return l.errorf("dynamic text value was not closed: eof")
1✔
383
        }
1✔
384
        l.backup()
1✔
385
        l.emit(tDynamicText)
1✔
386
        l.skip() // skip closing brace
1✔
387
        return lexHamlTextContent
1✔
388
}
389

390
func lexHamlDoctype(l *lexer) lexFn {
1✔
391
        l.skipRun("! ")
1✔
392
        l.acceptUntil("\n\r")
1✔
393
        l.emit(tDoctype)
1✔
394
        return lexHamlLineEnd
1✔
395
}
1✔
396

397
func lexHamlUnescaped(l *lexer) lexFn {
1✔
398
        l.skip()
1✔
399
        l.ignore()
1✔
400
        l.emit(tUnescaped)
1✔
401
        switch l.peek() {
1✔
402
        case '=':
1✔
403
                return lexHamlOutputCode
1✔
404
        default:
1✔
405
                return lexHamlTextStart
1✔
406
        }
407
}
408

409
func lexHamlSilentScript(l *lexer) lexFn {
1✔
410
        l.skip() // eat dash
1✔
411

1✔
412
        // ruby style comment
1✔
413
        if l.peek() == '#' {
2✔
414
                // ignore the rest of the line
1✔
415
                l.skipUntil("\n\r")
1✔
416
                l.emit(tRubyComment)
1✔
417
                return ignoreIndentedLines(l.indent+1, lexHamlLineStart)
1✔
418
        }
1✔
419

420
        l.skipRun(" \t")
1✔
421
        l.acceptUntil("\\\n\r")
1✔
422
        if n := l.peek(); n == '\\' || strings.HasSuffix(l.current(), ",") {
2✔
423
                if n == '\\' {
2✔
424
                        l.skip()
1✔
425
                }
1✔
426
                l.acceptRun("\n\r")
1✔
427
                return lexHamlCodeBlockIndent(l.indent+1, tSilentScript)
1✔
428
        }
429
        l.emit(tSilentScript)
1✔
430
        return lexHamlLineEnd
1✔
431
}
432

433
func lexHamlOutputCode(l *lexer) lexFn {
1✔
434
        l.skipRun("= \t")
1✔
435
        switch l.peek() {
1✔
436
        case '@':
1✔
437
                return lexHamlCommandCode
1✔
438
        default:
1✔
439
                l.acceptUntil("\\\n\r")
1✔
440
                if n := l.peek(); n == '\\' || strings.HasSuffix(l.current(), ",") {
2✔
441
                        if n == '\\' {
2✔
442
                                l.skip()
1✔
443
                        }
1✔
444
                        l.acceptRun("\n\r")
1✔
445
                        return lexHamlCodeBlockIndent(l.indent+1, tScript)
1✔
446
                }
447
                l.emit(tScript)
1✔
448
                return lexHamlLineEnd
1✔
449
        }
450
}
451

452
func lexHamlCodeBlockIndent(indent int, textType tokenType) lexFn {
1✔
453
        return func(l *lexer) lexFn {
2✔
454
                // only accept the whitespace that belongs to the indent
1✔
455

1✔
456
                // peeking first, in case we've reached the end of the block
1✔
457
                indents := l.peekAhead(indent)
1✔
458

1✔
459
                if len(strings.Trim(indents, "\t")) != 0 {
2✔
460
                        return l.errorf("expected continuation of code")
1✔
461
                }
1✔
462

463
                l.skipAhead(indent)
1✔
464

1✔
465
                return lexHamlCodeBlockContent(indent, textType)
1✔
466
        }
467
}
468

469
func lexHamlCodeBlockContent(indent int, textType tokenType) lexFn {
1✔
470
        return func(l *lexer) lexFn {
2✔
471
                l.acceptUntil("\\\n\r")
1✔
472
                if n := l.peek(); n == '\\' || strings.HasSuffix(l.current(), ",") {
2✔
473
                        if n == '\\' {
1✔
474
                                l.skip()
×
475
                        }
×
476
                        l.acceptRun("\n\r")
1✔
477
                        return lexHamlCodeBlockIndent(indent, textType)
1✔
478
                }
479
                l.acceptRun("\n\r")
1✔
480
                l.emit(textType)
1✔
481

1✔
482
                return lexHamlLineStart
1✔
483
        }
484
}
485

486
func lexHamlComment(l *lexer) lexFn {
1✔
487
        l.skipRun("/ \t")
1✔
488
        l.acceptUntil("\n\r")
1✔
489
        l.emit(tComment)
1✔
490
        return lexHamlLineEnd
1✔
491
}
1✔
492

493
func lexHamlVoidTag(l *lexer) lexFn {
1✔
494
        l.skipRun("/ \t")
1✔
495
        l.acceptUntil("\n\r")
1✔
496
        if l.current() != "" {
2✔
497
                l.ignore()
1✔
498
                return l.errorf("self-closing tags can't have content")
1✔
499
        }
1✔
500
        l.emit(tVoidTag)
1✔
501
        return lexHamlLineEnd
1✔
502
}
503

504
func lexHamlCommandCode(l *lexer) lexFn {
1✔
505
        l.skipRun("@")
1✔
506
        l.acceptUntil("() \t\n\r")
1✔
507
        if l.current() == "" {
2✔
508
                return l.errorf("command code expected")
1✔
509
        }
1✔
510
        switch l.current() {
1✔
511
        case "render":
1✔
512
                l.acceptRun("() \t")
1✔
513
                l.ignore()
1✔
514
                l.acceptUntil("\\\n\r")
1✔
515
                if l.current() == "" {
2✔
516
                        return l.errorf("render argument expected")
1✔
517
                }
1✔
518
                if n := l.peek(); n == '\\' || strings.HasSuffix(l.current(), ",") {
2✔
519
                        if n == '\\' {
2✔
520
                                l.skip()
1✔
521
                        }
1✔
522
                        l.acceptRun("\n\r")
1✔
523
                        return lexHamlCodeBlockIndent(l.indent+1, tRenderCommand)
1✔
524
                }
525
                l.emit(tRenderCommand)
1✔
526
        case "children":
1✔
527
                l.acceptRun("() \t")
1✔
528
                l.ignore()
1✔
529
                l.acceptUntil("\n\r")
1✔
530
                if l.current() != "" {
2✔
531
                        return l.errorf("children command does not accept arguments")
1✔
532
                }
1✔
533
                l.emit(tChildrenCommand)
1✔
534
        case "slot":
1✔
535
                l.acceptRun("() \t")
1✔
536
                l.ignore()
1✔
537
                l.acceptUntil("\n\r")
1✔
538
                if l.current() == "" {
2✔
539
                        return l.errorf("slot name expected")
1✔
540
                }
1✔
541
                l.emit(tSlotCommand)
1✔
542
        default:
1✔
543
                return l.errorf("unknown command: %s", l.current())
1✔
544
        }
545
        l.skipRun("\n\r")
1✔
546
        return lexHamlLineStart
1✔
547
}
548

549
var hamlFilters = []string{"javascript", "css", "plain", "escaped", "preserve"}
550

551
func lexHamlFilterStart(l *lexer) lexFn {
1✔
552
        l.skipRun(": \t")
1✔
553
        l.acceptUntil(" \t\n\r")
1✔
554
        if l.current() == "" {
2✔
555
                return l.errorf("filter name expected")
1✔
556
        }
1✔
557
        if !slices.Contains(hamlFilters, l.current()) {
2✔
558
                return l.errorf("unknown filter: %s", l.current())
1✔
559
        }
1✔
560
        filter := l.current()
1✔
561
        l.emit(tFilterStart)
1✔
562
        l.skipUntil("\n\r") // ignore the rest of the current line
1✔
563
        l.skipRun("\n\r")   // split so we don't consume the indent on the next line
1✔
564

1✔
565
        switch filter {
1✔
566
        case "javascript", "css", "plain":
1✔
567
                return lexHamlFilterLineStart(l.indent+1, tPlainText)
1✔
568
        case "escaped":
1✔
569
                return lexHamlFilterLineStart(l.indent+1, tEscapedText)
1✔
570
        case "preserve":
1✔
571
                return lexHamlFilterLineStart(l.indent+1, tPreserveText)
1✔
572
        default:
×
573
                return l.errorf("unsupported filter: %s", filter)
×
574
        }
575
}
576

577
func lexHamlFilterLineStart(indent int, textType tokenType) lexFn {
1✔
578
        return func(l *lexer) lexFn {
2✔
579
                switch l.peek() {
1✔
580
                case ' ', '\t':
1✔
581
                        return lexHamlFilterIndent(indent, textType)
1✔
582
                case scanner.EOF:
1✔
583
                        l.emit(tEOF)
1✔
584
                        return nil
1✔
585
                default:
1✔
586
                        l.emit(tFilterEnd)
1✔
587
                        return lexHamlLineStart
1✔
588
                }
589
        }
590
}
591

592
func lexHamlFilterIndent(indent int, textType tokenType) lexFn {
1✔
593
        return func(l *lexer) lexFn {
2✔
594
                var indents string
1✔
595

1✔
596
                // peeking first, in case we've reached the end of the filter
1✔
597
                indents = l.peekAhead(indent)
1✔
598

1✔
599
                // trim the tabs from what we've peeked into; no longer using TrimSpace as that would trim spaces and newlines
1✔
600
                if len(strings.Trim(indents, "\t")) != 0 {
2✔
601
                        l.emit(tFilterEnd)
1✔
602
                        return lexHamlLineStart
1✔
603
                }
1✔
604

605
                l.skipAhead(indent)
1✔
606

1✔
607
                return lexHamlFilterContent(indent, textType)
1✔
608
        }
609
}
610

611
func lexHamlFilterContent(indent int, textType tokenType) lexFn {
1✔
612
        return func(l *lexer) lexFn {
2✔
613
                l.acceptUntil("#\n\r")
1✔
614
                if l.peek() == '#' {
2✔
615
                        return lexHamlFilterDynamicText(textType, lexHamlFilterContent(indent, textType))
1✔
616
                }
1✔
617
                l.acceptRun("\n\r")
1✔
618
                if l.current() != "" {
2✔
619
                        l.emit(textType)
1✔
620
                }
1✔
621
                return lexHamlFilterLineStart(indent, textType)
1✔
622
        }
623
}
624

625
func lexHamlFilterDynamicText(textType tokenType, next lexFn) lexFn {
1✔
626
        return func(l *lexer) lexFn {
2✔
627
                if s := l.peekAhead(2); s != "#{" {
2✔
628
                        l.next()
1✔
629
                        return next
1✔
630
                }
1✔
631
                if l.current() != "" {
2✔
632
                        l.emit(textType)
1✔
633
                }
1✔
634
                l.skipAhead(2) // skip the hash and opening brace
1✔
635
                r := continueToMatchingBrace(l, '}', false)
1✔
636
                if r == scanner.EOF {
2✔
637
                        return l.errorf("dynamic text value was not closed: eof")
1✔
638
                }
1✔
639
                l.backup()
1✔
640
                l.emit(tDynamicText)
1✔
641
                l.skip() // skip closing brace
1✔
642
                return next
1✔
643
        }
644
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc