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

source-academy / js-slang / 13750610219

09 Mar 2025 05:01PM UTC coverage: 81.086% (-0.04%) from 81.126%
13750610219

Pull #1741

github

web-flow
Merge 561e360c2 into 6aad26cce
Pull Request #1741: Bump prettier, ace-builds, and misc clean up

3438 of 4606 branches covered (74.64%)

Branch coverage included in aggregate %.

66 of 89 new or added lines in 12 files covered. (74.16%)

9 existing lines in 4 files now uncovered.

10782 of 12931 relevant lines covered (83.38%)

143543.43 hits per line

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

51.57
/src/editors/ace/modes/source.ts
1
import { Variant } from '../../../types'
1✔
2
import { SourceDocumentation } from '../docTooltip'
1✔
3

4
/* tslint:disable */
5

6
/**
7
 * Source Mode for Ace Editor
8
 * (Modified from javascript mode in default brace package)
9
 * The link to the original JavaScript mode can be found here:
10
 * https://github.com/ajaxorg/ace-builds/blob/master/src/mode-javascript.js
11
 *
12
 * Changes includes:
13
 * 1) change code styles so that it passes tslint test
14
 * 2) refactor some code to ES2015 class syntax
15
 * 3) Encapsulate the orginal mode and higlightrules in two selectors so as to change according to source chapter
16
 * 4) changed regex to mark certain operators in pink
17
 * 5) use SourceDocumentation to include all library functions and constants from source
18
 * 6) include all external libraries
19
 */
20

21
export function HighlightRulesSelector(
1✔
22
  id: number,
23
  variant: Variant = Variant.DEFAULT,
×
24
  external: string = 'NONE',
×
25
  externalLibraries: (
7✔
26
    | {
27
        caption: string
28
        value: string
29
        meta: any
30
        docHTML: any
31
      }
32
    | {
33
        caption: string
34
        value: string
35
        meta: string
36
        docHTML?: undefined
37
      }
38
  )[] = []
39
) {
40
  // @ts-ignore
41
  function _SourceHighlightRules(acequire, exports, _module) {
42
    'use strict'
43

44
    const oop = acequire('../lib/oop')
3✔
45
    const DocCommentHighlightRules = acequire(
3✔
46
      './doc_comment_highlight_rules'
47
    ).DocCommentHighlightRules
48
    const TextHighlightRules = acequire('./text_highlight_rules').TextHighlightRules
3✔
49
    const identifierRegex = '[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\\d\\$_\u00a1-\uffff]*'
3✔
50

51
    const chapter = variant === Variant.DEFAULT ? id.toString() : id.toString() + '_' + variant
3!
52
    const builtin_lib = SourceDocumentation.builtins[chapter]
3✔
53

54
    function addFromBuiltinLibrary(meta: string) {
55
      if (builtin_lib === null) {
6!
56
        return ''
×
57
      }
58
      let func = ''
6✔
59
      for (const name in builtin_lib) {
6✔
UNCOV
60
        if (builtin_lib[name]['meta'] === meta) {
×
UNCOV
61
          func += '|' + name
×
62
        }
63
      }
64
      return func
6✔
65
    }
66

67
    function addFromExternalLibrary(meta: string) {
68
      if (externalLibraries === null) {
6!
69
        return ''
×
70
      }
71
      let func = ''
6✔
72
      externalLibraries.forEach(node => {
6✔
73
        if (node.meta === meta) {
×
74
          func += '|' + node.caption
×
75
        }
76
      })
77
      return func
6✔
78
    }
79

80
    function getAllNames(meta: string) {
81
      const concat = addFromBuiltinLibrary(meta) + addFromExternalLibrary(meta)
6✔
82
      return concat.substr(1)
6✔
83
    }
84

85
    const ChapterKeywordSelector = () => {
3✔
86
      const output = []
3✔
87
      if (id >= 1) {
3✔
88
        output.push('import', 'const', 'else', 'if', 'return', 'function', 'debugger')
3✔
89
      }
90
      if (id >= 2) {
3✔
91
        output.push('export')
2✔
92
      }
93
      if (id >= 3) {
3✔
94
        output.push('while', 'for', 'break', 'continue', 'let')
1✔
95
      }
96
      return output.join('|')
3✔
97
    }
98

99
    const ChapterAndVariantForbiddenWordSelector = () => {
3✔
100
      const forbiddenWords = []
3✔
101
      if (id < 2) {
3✔
102
        forbiddenWords.push('export')
1✔
103
      }
104
      if (id < 3) {
3✔
105
        forbiddenWords.push('while', 'for', 'break', 'continue', 'let')
2✔
106
      }
107
      if (variant !== Variant.TYPED) {
3✔
108
        forbiddenWords.push('typeof', 'void')
3✔
109
      }
110
      return forbiddenWords.join('|')
3✔
111
    }
112

113
    const VariantForbiddenRegexSelector = () => {
3✔
114
      if (variant === Variant.TYPED) {
3!
115
        // Removes the part of the regex that highlights singular |, since Typed variant uses union types
116
        return /\.{3}|--+|\+\++|\^|(==|!=)[^=]|[$%&*+\-~\/^]=+|(?<!&)&(?!&)/
×
117
      }
118
      return /\.{3}|--+|\+\++|\^|(==|!=)[^=]|[$%&*+\-~\/^]=+|(?<!&)&(?!&)|(?<!\|)\|(?!\|)/
3✔
119
    }
120

121
    // Documentation for token types:
122
    // https://github.com/ajaxorg/ace/wiki/Creating-or-Extending-an-Edit-Mode#common-tokens
123
    // @ts-ignore
124
    const SourceHighlightRules = function (options) {
3✔
125
      // @ts-ignore
126
      const keywordMapper = this.createKeywordMapper(
3✔
127
        {
128
          builtinconsts: getAllNames('const'),
129

130
          'constant.language.boolean': 'true|false',
131
          'constant.language.null': 'null',
132

133
          keyword: ChapterKeywordSelector(),
134

135
          'storage.type': 'const|let|function',
136

137
          'support.function': getAllNames('func'),
138

139
          'variable.language':
140
            'this|arguments|' + // Pseudo
141
            'var|yield|async|await|with|switch|throw|try|eval|' + // forbidden words
142
            'class|enum|extends|super|implements|private|public|' +
143
            'interface|package|protected|static|in|of|instanceof|new|' +
144
            'case|catch|default|delete|do|finally|' +
145
            ChapterAndVariantForbiddenWordSelector()
146
        },
147
        'identifier'
148
      )
149

150
      // original keywordBeforeRegex = "case|do|else|finally|in|instanceof|return|throw|try|typeof|yield|void";
151
      const keywordBeforeRegex = 'else|return'
3✔
152

153
      const escapedRegex =
154
        '\\\\(?:x[0-9a-fA-F]{2}|' + // hex
3✔
155
        'u[0-9a-fA-F]{4}|' + // unicode
156
        'u{[0-9a-fA-F]{1,6}}|' + // es6 unicode
157
        '[0-2][0-7]{0,2}|' + // oct
158
        '3[0-7][0-7]?|' + // oct
159
        '[4-7][0-7]?|' + //oct
160
        '.)'
161

162
      // @ts-ignore
163
      this.$rules = {
3✔
164
        no_regex: [
165
          DocCommentHighlightRules.getStartRule('doc-start'),
166
          comments('no_regex'),
167
          {
168
            token: 'string',
169
            regex: "'(?=.)",
170
            next: 'qstring'
171
          },
172
          {
173
            token: 'string',
174
            regex: '"(?=.)',
175
            next: 'qqstring'
176
          },
177
          {
178
            token: 'constant.numeric', // hexadecimal, octal and binary
179
            regex: /0(?:[xX][0-9a-fA-F]+|[oO][0-7]+|[bB][01]+)\b/
180
          },
181
          {
182
            token: 'constant.numeric', // decimal integers and floats
183
            regex: /(?:\d\d*(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+\b)?/
184
          },
185
          {
186
            token: [
187
              'storage.type',
188
              'punctuation.operator',
189
              'support.function',
190
              'punctuation.operator',
191
              'entity.name.function',
192
              'text',
193
              'keyword.operator'
194
            ],
195
            regex:
196
              '(' + identifierRegex + ')(\\.)(prototype)(\\.)(' + identifierRegex + ')(\\s*)(=)',
197
            next: 'function_arguments'
198
          },
199
          {
200
            token: [
201
              'storage.type',
202
              'punctuation.operator',
203
              'entity.name.function',
204
              'text',
205
              'keyword.operator',
206
              'text',
207
              'storage.type',
208
              'text',
209
              'paren.lparen'
210
            ],
211
            regex:
212
              '(' +
213
              identifierRegex +
214
              ')(\\.)(' +
215
              identifierRegex +
216
              ')(\\s*)(=)(\\s*)(function)(\\s*)(\\()',
217
            next: 'function_arguments'
218
          },
219
          {
220
            token: [
221
              'entity.name.function',
222
              'text',
223
              'keyword.operator',
224
              'text',
225
              'storage.type',
226
              'text',
227
              'paren.lparen'
228
            ],
229
            regex: '(' + identifierRegex + ')(\\s*)(=)(\\s*)(function)(\\s*)(\\()',
230
            next: 'function_arguments'
231
          },
232
          {
233
            token: [
234
              'storage.type',
235
              'punctuation.operator',
236
              'entity.name.function',
237
              'text',
238
              'keyword.operator',
239
              'text',
240
              'storage.type',
241
              'text',
242
              'entity.name.function',
243
              'text',
244
              'paren.lparen'
245
            ],
246
            regex:
247
              '(' +
248
              identifierRegex +
249
              ')(\\.)(' +
250
              identifierRegex +
251
              ')(\\s*)(=)(\\s*)(function)(\\s+)(\\w+)(\\s*)(\\()',
252
            next: 'function_arguments'
253
          },
254
          {
255
            token: ['storage.type', 'text', 'entity.name.function', 'text', 'paren.lparen'],
256
            regex: '(function)(\\s+)(' + identifierRegex + ')(\\s*)(\\()',
257
            next: 'function_arguments'
258
          },
259
          {
260
            token: [
261
              'entity.name.function',
262
              'text',
263
              'punctuation.operator',
264
              'text',
265
              'storage.type',
266
              'text',
267
              'paren.lparen'
268
            ],
269
            regex: '(' + identifierRegex + ')(\\s*)(:)(\\s*)(function)(\\s*)(\\()',
270
            next: 'function_arguments'
271
          },
272
          {
273
            token: ['text', 'text', 'storage.type', 'text', 'paren.lparen'],
274
            regex: '(:)(\\s*)(function)(\\s*)(\\()',
275
            next: 'function_arguments'
276
          },
277
          {
278
            token: 'keyword',
279
            regex: 'from(?=\\s*(\'|"))'
280
          },
281
          {
282
            token: 'keyword',
283
            regex: '(?:' + keywordBeforeRegex + ')\\b',
284
            next: 'start'
285
          },
286
          {
287
            token: ['support.constant'],
288
            regex: /that\b/
289
          },
290
          {
291
            token: ['variable.language'],
292
            regex: VariantForbiddenRegexSelector()
293
          },
294
          {
295
            token: keywordMapper,
296
            regex: identifierRegex
297
          },
298
          {
299
            token: 'variable.language',
300
            regex: /[.](?![.])/,
301
            next: 'property'
302
          },
303
          {
304
            token: 'storage.type',
305
            regex: /=>/
306
          },
307
          {
308
            token: 'keyword.operator',
309
            regex: /===|=|!==|<+=?|>+=?|!|&&|\|\||[%*+-\/]/,
310
            next: 'start'
311
          },
312
          {
313
            token: 'punctuation.operator',
314
            regex: /[?:,;.]/,
315
            next: 'start'
316
          },
317
          {
318
            token: 'paren.lparen',
319
            regex: /[\[({]/,
320
            next: 'start'
321
          },
322
          {
323
            token: 'paren.rparen',
324
            regex: /[\])}]/
325
          },
326
          {
327
            token: 'comment',
328
            regex: /^#!.*$/
329
          }
330
        ],
331
        property: [
332
          {
333
            token: 'text',
334
            regex: '\\s+'
335
          },
336
          {
337
            token: [
338
              'storage.type',
339
              'punctuation.operator',
340
              'entity.name.function',
341
              'text',
342
              'keyword.operator',
343
              'text',
344
              'storage.type',
345
              'text',
346
              'entity.name.function',
347
              'text',
348
              'paren.lparen'
349
            ],
350
            regex:
351
              '(' +
352
              identifierRegex +
353
              ')(\\.)(' +
354
              identifierRegex +
355
              ')(\\s*)(=)(\\s*)(function)(?:(\\s+)(\\w+))?(\\s*)(\\()',
356
            next: 'function_arguments'
357
          },
358
          {
359
            token: 'punctuation.operator',
360
            regex: /[.](?![.])/
361
          },
362
          {
363
            token: 'variable.language',
364
            regex:
365
              /(s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:op|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\b(?=\()/
366
          },
367
          {
368
            token: 'variable.language.dom',
369
            regex:
370
              /(s(?:ub(?:stringData|mit)|plitText|e(?:t(?:NamedItem|Attribute(?:Node)?)|lect))|has(?:ChildNodes|Feature)|namedItem|c(?:l(?:ick|o(?:se|neNode))|reate(?:C(?:omment|DATASection|aption)|T(?:Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(?:ntityReference|lement)|Attribute))|tabIndex|i(?:nsert(?:Row|Before|Cell|Data)|tem)|open|delete(?:Row|C(?:ell|aption)|T(?:Head|Foot)|Data)|focus|write(?:ln)?|a(?:dd|ppend(?:Child|Data))|re(?:set|place(?:Child|Data)|move(?:NamedItem|Child|Attribute(?:Node)?)?)|get(?:NamedItem|Element(?:sBy(?:Name|TagName|ClassName)|ById)|Attribute(?:Node)?)|blur)\b(?=\()/
371
          },
372
          {
373
            token: 'support.constant',
374
            regex:
375
              /(s(?:ystemLanguage|cr(?:ipts|ollbars|een(?:X|Y|Top|Left))|t(?:yle(?:Sheets)?|atus(?:Text|bar)?)|ibling(?:Below|Above)|ource|uffixes|e(?:curity(?:Policy)?|l(?:ection|f)))|h(?:istory|ost(?:name)?|as(?:h|Focus))|y|X(?:MLDocument|SLDocument)|n(?:ext|ame(?:space(?:s|URI)|Prop))|M(?:IN_VALUE|AX_VALUE)|c(?:haracterSet|o(?:n(?:structor|trollers)|okieEnabled|lorDepth|mp(?:onents|lete))|urrent|puClass|l(?:i(?:p(?:boardData)?|entInformation)|osed|asses)|alle(?:e|r)|rypto)|t(?:o(?:olbar|p)|ext(?:Transform|Indent|Decoration|Align)|ags)|SQRT(?:1_2|2)|i(?:n(?:ner(?:Height|Width)|put)|ds|gnoreCase)|zIndex|o(?:scpu|n(?:readystatechange|Line)|uter(?:Height|Width)|p(?:sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(?:i(?:splay|alog(?:Height|Top|Width|Left|Arguments)|rectories)|e(?:scription|fault(?:Status|Ch(?:ecked|arset)|View)))|u(?:ser(?:Profile|Language|Agent)|n(?:iqueID|defined)|pdateInterval)|_content|p(?:ixelDepth|ort|ersonalbar|kcs11|l(?:ugins|atform)|a(?:thname|dding(?:Right|Bottom|Top|Left)|rent(?:Window|Layer)?|ge(?:X(?:Offset)?|Y(?:Offset)?))|r(?:o(?:to(?:col|type)|duct(?:Sub)?|mpter)|e(?:vious|fix)))|e(?:n(?:coding|abledPlugin)|x(?:ternal|pando)|mbeds)|v(?:isibility|endor(?:Sub)?|Linkcolor)|URLUnencoded|P(?:I|OSITIVE_INFINITY)|f(?:ilename|o(?:nt(?:Size|Family|Weight)|rmName)|rame(?:s|Element)|gColor)|E|whiteSpace|l(?:i(?:stStyleType|n(?:eHeight|kColor))|o(?:ca(?:tion(?:bar)?|lName)|wsrc)|e(?:ngth|ft(?:Context)?)|a(?:st(?:M(?:odified|atch)|Index|Paren)|yer(?:s|X)|nguage))|a(?:pp(?:MinorVersion|Name|Co(?:deName|re)|Version)|vail(?:Height|Top|Width|Left)|ll|r(?:ity|guments)|Linkcolor|bove)|r(?:ight(?:Context)?|e(?:sponse(?:XML|Text)|adyState))|global|x|m(?:imeTypes|ultiline|enubar|argin(?:Right|Bottom|Top|Left))|L(?:N(?:10|2)|OG(?:10E|2E))|b(?:o(?:ttom|rder(?:Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(?:Color|Image)))\b/
376
          },
377
          {
378
            token: 'identifier',
379
            regex: identifierRegex
380
          },
381
          {
382
            regex: '',
383
            token: 'empty',
384
            next: 'no_regex'
385
          }
386
        ],
387
        start: [
388
          DocCommentHighlightRules.getStartRule('doc-start'),
389
          comments('start'),
390
          {
391
            token: 'string.regexp',
392
            regex: '\\/',
393
            next: 'regex'
394
          },
395
          {
396
            token: 'text',
397
            regex: '\\s+|^$',
398
            next: 'start'
399
          },
400
          {
401
            token: 'empty',
402
            regex: '',
403
            next: 'no_regex'
404
          }
405
        ],
406
        regex: [
407
          {
408
            token: 'regexp.keyword.operator',
409
            regex: '\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)'
410
          },
411
          {
412
            token: 'string.regexp',
413
            regex: '/[sxngimy]*',
414
            next: 'no_regex'
415
          },
416
          {
417
            token: 'invalid',
418
            regex: /\{\d+\b,?\d*\}[+*]|[+*$^?][+*]|[$^][?]|\?{3,}/
419
          },
420
          {
421
            token: 'constant.language.escape',
422
            regex: /\(\?[:=!]|\)|\{\d+\b,?\d*\}|[+*]\?|[()$^+*?.]/
423
          },
424
          {
425
            token: 'constant.language.delimiter',
426
            regex: /\|/
427
          },
428
          {
429
            token: 'constant.language.escape',
430
            regex: /\[\^?/,
431
            next: 'regex_character_class'
432
          },
433
          {
434
            token: 'empty',
435
            regex: '$',
436
            next: 'no_regex'
437
          },
438
          {
439
            defaultToken: 'string.regexp'
440
          }
441
        ],
442
        regex_character_class: [
443
          {
444
            token: 'regexp.charclass.keyword.operator',
445
            regex: '\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)'
446
          },
447
          {
448
            token: 'constant.language.escape',
449
            regex: ']',
450
            next: 'regex'
451
          },
452
          {
453
            token: 'constant.language.escape',
454
            regex: '-'
455
          },
456
          {
457
            token: 'empty',
458
            regex: '$',
459
            next: 'no_regex'
460
          },
461
          {
462
            defaultToken: 'string.regexp.charachterclass'
463
          }
464
        ],
465
        function_arguments: [
466
          {
467
            token: 'variable.parameter',
468
            regex: identifierRegex
469
          },
470
          {
471
            token: 'punctuation.operator',
472
            regex: '[, ]+'
473
          },
474
          {
475
            token: 'punctuation.operator',
476
            regex: '$'
477
          },
478
          {
479
            token: 'empty',
480
            regex: '',
481
            next: 'no_regex'
482
          }
483
        ],
484
        qqstring: [
485
          {
486
            token: 'constant.language.escape',
487
            regex: escapedRegex
488
          },
489
          {
490
            token: 'string',
491
            regex: '\\\\$',
492
            consumeLineEnd: true
493
          },
494
          {
495
            token: 'string',
496
            regex: '"|$',
497
            next: 'no_regex'
498
          },
499
          {
500
            defaultToken: 'string'
501
          }
502
        ],
503
        qstring: [
504
          {
505
            token: 'constant.language.escape',
506
            regex: escapedRegex
507
          },
508
          {
509
            token: 'string',
510
            regex: '\\\\$',
511
            consumeLineEnd: true
512
          },
513
          {
514
            token: 'string',
515
            regex: "'|$",
516
            next: 'no_regex'
517
          },
518
          {
519
            defaultToken: 'string'
520
          }
521
        ]
522
      }
523

524
      if (!options || !options.noES6) {
3!
525
        // @ts-ignore
526
        this.$rules.no_regex.unshift(
3✔
527
          {
528
            regex: '[{}]',
529
            // @ts-ignore
530
            onMatch: function (val, state, stack) {
531
              this.next = val == '{' ? this.nextState : ''
4✔
532
              if (val == '{' && stack.length) {
4!
533
                stack.unshift('start', state)
×
534
              } else if (val == '}' && stack.length) {
4!
535
                stack.shift()
×
536
                this.next = stack.shift()
×
537
                if (this.next.indexOf('string') != -1 || this.next.indexOf('jsx') != -1)
×
538
                  return 'paren.quasi.end'
×
539
              }
540
              return val == '{' ? 'paren.lparen' : 'paren.rparen'
4✔
541
            },
542
            nextState: 'start'
543
          },
544
          {
545
            token: 'string.quasi.start',
546
            regex: /`/,
547
            push: [
548
              {
549
                token: 'constant.language.escape',
550
                regex: escapedRegex
551
              },
552
              {
553
                token: 'paren.quasi.start',
554
                regex: /\${/,
555
                push: 'start'
556
              },
557
              {
558
                token: 'string.quasi.end',
559
                regex: /`/,
560
                next: 'pop'
561
              },
562
              {
563
                defaultToken: 'string.quasi'
564
              }
565
            ]
566
          }
567
        )
568

569
        if (!options || options.jsx != false)
3!
570
          // @ts-ignore
571
          JSX.call(this)
3✔
572

573
        // Adding of highlight rules for Source Typed
574
        // Code referenced from https://github.com/ajaxorg/ace-builds/blob/master/src/mode-typescript.js
575
        if (variant === Variant.TYPED) {
3!
576
          // @ts-ignore
577
          this.$rules.no_regex.unshift(
×
578
            {
579
              token: ['storage.type', 'text', 'entity.name.function.ts'],
580
              regex: '(function)(\\s+)([a-zA-Z0-9$_\u00a1-\uffff][a-zA-Z0-9d$_\u00a1-\uffff]*)'
581
            },
582
            {
583
              token: ['keyword', 'storage.type.variable.ts'],
584
              regex: '(type)(\\s+[a-zA-Z0-9_?.$][\\w?.$]*)'
585
            },
586
            {
587
              token: 'keyword',
588
              regex: '\\b(?:typeof)\\b'
589
            }
590
          )
591
        }
592
      }
593
      // @ts-ignore
594
      this.embedRules(DocCommentHighlightRules, 'doc-', [
3✔
595
        DocCommentHighlightRules.getEndRule('no_regex')
596
      ])
597
      // @ts-ignore
598
      this.normalizeRules()
3✔
599
    }
600

601
    oop.inherits(SourceHighlightRules, TextHighlightRules)
3✔
602

603
    function JSX() {
604
      const tagRegex = identifierRegex.replace('\\d', '\\d\\-')
3✔
605
      const jsxTag = {
3✔
606
        // @ts-ignore
607
        onMatch: function (val, state, stack) {
608
          const offset = val.charAt(1) == '/' ? 2 : 1
×
609
          if (offset == 1) {
×
610
            if (state != this.nextState) stack.unshift(this.next, this.nextState, 0)
×
611
            else stack.unshift(this.next)
×
612
            stack[2]++
×
613
          } else if (offset == 2) {
×
614
            if (state == this.nextState) {
×
615
              stack[1]--
×
616
              if (!stack[1] || stack[1] < 0) {
×
617
                stack.shift()
×
618
                stack.shift()
×
619
              }
620
            }
621
          }
622
          return [
×
623
            {
624
              type: 'meta.tag.punctuation.' + (offset == 1 ? '' : 'end-') + 'tag-open.xml',
×
625
              value: val.slice(0, offset)
626
            },
627
            {
628
              type: 'meta.tag.tag-name.xml',
629
              value: val.substr(offset)
630
            }
631
          ]
632
        },
633
        regex: '</?' + tagRegex + '',
634
        next: 'jsxAttributes',
635
        nextState: 'jsx'
636
      }
637
      // @ts-ignore
638
      this.$rules.start.unshift(jsxTag)
3✔
639
      const jsxJsRule = {
3✔
640
        regex: '{',
641
        token: 'paren.quasi.start',
642
        push: 'start'
643
      }
644
      // @ts-ignore
645
      this.$rules.jsx = [jsxJsRule, jsxTag, { include: 'reference' }, { defaultToken: 'string' }]
3✔
646
      // @ts-ignore
647
      this.$rules.jsxAttributes = [
3✔
648
        {
649
          token: 'meta.tag.punctuation.tag-close.xml',
650
          regex: '/?>',
651
          // @ts-ignore
652
          onMatch: function (value, currentState, stack) {
653
            if (currentState == stack[0]) stack.shift()
×
654
            if (value.length == 2) {
×
655
              if (stack[0] == this.nextState) stack[1]--
×
656
              if (!stack[1] || stack[1] < 0) {
×
657
                stack.splice(0, 2)
×
658
              }
659
            }
660
            // @ts-ignore
661
            this.next = stack[0] || 'start'
×
662
            return [{ type: this.token, value: value }]
×
663
          },
664
          nextState: 'jsx'
665
        },
666
        jsxJsRule,
667
        comments('jsxAttributes'),
668
        {
669
          token: 'entity.other.attribute-name.xml',
670
          regex: tagRegex
671
        },
672
        {
673
          token: 'keyword.operator.attribute-equals.xml',
674
          regex: '='
675
        },
676
        {
677
          token: 'text.tag-whitespace.xml',
678
          regex: '\\s+'
679
        },
680
        {
681
          token: 'string.attribute-value.xml',
682
          regex: "'",
683
          stateName: 'jsx_attr_q',
684
          push: [
685
            { token: 'string.attribute-value.xml', regex: "'", next: 'pop' },
686
            { include: 'reference' },
687
            { defaultToken: 'string.attribute-value.xml' }
688
          ]
689
        },
690
        {
691
          token: 'string.attribute-value.xml',
692
          regex: '"',
693
          stateName: 'jsx_attr_qq',
694
          push: [
695
            { token: 'string.attribute-value.xml', regex: '"', next: 'pop' },
696
            { include: 'reference' },
697
            { defaultToken: 'string.attribute-value.xml' }
698
          ]
699
        },
700
        jsxTag
701
      ]
702
      // @ts-ignore
703
      this.$rules.reference = [
3✔
704
        {
705
          token: 'constant.language.escape.reference.xml',
706
          regex: '(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\.-]+;)'
707
        }
708
      ]
709
    }
710

711
    // @ts-ignore
712
    function comments(next) {
713
      return [
9✔
714
        {
715
          token: 'comment', // multi line comment
716
          regex: /\/\*/,
717
          next: [
718
            DocCommentHighlightRules.getTagRule(),
719
            { token: 'comment', regex: '\\*\\/', next: next || 'pop' },
9!
720
            { defaultToken: 'comment', caseInsensitive: true }
721
          ]
722
        },
723
        {
724
          token: 'comment',
725
          regex: '\\/\\/',
726
          next: [
727
            DocCommentHighlightRules.getTagRule(),
728
            { token: 'comment', regex: '$|^', next: next || 'pop' },
9!
729
            { defaultToken: 'comment', caseInsensitive: true }
730
          ]
731
        }
732
      ]
733
    }
734
    exports.SourceHighlightRules = SourceHighlightRules
3✔
735
  }
736

737
  const name = id.toString() + variant + external
7✔
738

739
  // @ts-ignore
740
  ace.define(
7✔
741
    'ace/mode/source_highlight_rules' + name,
742
    [
743
      'require',
744
      'exports',
745
      'module',
746
      'ace/lib/oop',
747
      'ace/mode/doc_comment_highlight_rules',
748
      'ace/mode/text_highlight_rules'
749
    ],
750
    _SourceHighlightRules
751
  )
752
}
753

754
//source mode
755
export function ModeSelector(
1✔
756
  id: number,
757
  variant: Variant = Variant.DEFAULT,
×
758
  external: string = 'NONE'
×
759
) {
760
  const name = id.toString() + variant + external
7✔
761

762
  // @ts-ignore
763
  function _Mode(acequire, exports, _module) {
764
    'use strict'
765

766
    const oop = acequire('../lib/oop')
3✔
767
    const TextMode = acequire('./text').Mode
3✔
768
    const SourceHighlightRules = acequire('./source_highlight_rules' + name).SourceHighlightRules
3✔
769
    const MatchingBraceOutdent = acequire('./matching_brace_outdent').MatchingBraceOutdent
3✔
770
    // For JSHint background worker
771
    // const WorkerClient = acequire('../worker/worker_client').WorkerClient
772
    const CstyleBehaviour = acequire('./behaviour/cstyle').CstyleBehaviour
3✔
773
    const CStyleFoldMode = acequire('./folding/cstyle').FoldMode
3✔
774

775
    const Mode = function () {
3✔
776
      // @ts-ignore
777
      this.HighlightRules = SourceHighlightRules
3✔
778
      // @ts-ignore
779
      this.$outdent = new MatchingBraceOutdent()
3✔
780
      // @ts-ignore
781
      this.$behaviour = new CstyleBehaviour()
3✔
782
      // @ts-ignore
783
      this.foldingRules = new CStyleFoldMode()
3✔
784
    }
785
    oop.inherits(Mode, TextMode)
3✔
786
    ;(function () {
3✔
787
      // @ts-ignore
788
      this.lineCommentStart = '//'
3✔
789
      // @ts-ignore
790
      this.blockComment = { start: '/*', end: '*/' }
3✔
791
      // @ts-ignore
792
      this.$quotes = { '"': '"', "'": "'", '`': '`' }
3✔
793

794
      // @ts-ignore
795
      this.getNextLineIndent = function (state, line, tab) {
3✔
796
        let indent = this.$getIndent(line)
×
797

798
        const tokenizedLine = this.getTokenizer().getLineTokens(line, state)
×
799
        const tokens = tokenizedLine.tokens
×
800
        const endState = tokenizedLine.state
×
801

802
        if (tokens.length && tokens[tokens.length - 1].type == 'comment') {
×
803
          return indent
×
804
        }
805

806
        if (state == 'start' || state == 'no_regex') {
×
807
          const match = line.match(/^.*(?:\bcase\b.*:|[\{\(\[])\s*$/)
×
808
          if (match) {
×
809
            indent += tab
×
810
          }
811
        } else if (state == 'doc-start') {
×
812
          if (endState == 'start' || endState == 'no_regex') {
×
813
            return ''
×
814
          }
815
          const match = line.match(/^\s*(\/?)\*/)
×
816
          if (match) {
×
817
            if (match[1]) {
×
818
              indent += ' '
×
819
            }
820
            indent += '* '
×
821
          }
822
        }
823

824
        return indent
×
825
      }
826

827
      // @ts-ignore
828
      this.checkOutdent = function (state, line, input) {
3✔
829
        return this.$outdent.checkOutdent(line, input)
×
830
      }
831

832
      // @ts-ignore
833
      this.autoOutdent = function (state, doc, row) {
3✔
834
        this.$outdent.autoOutdent(doc, row)
×
835
      }
836

837
      // This is the JSHint background worker. Disabled because it is of little
838
      // utility to Source, and produced many false positives.
839
      // If this is ever enabled again: the *frontend* needs to provide the URL of
840
      // the worker to Ace:
841
      //
842
      // import jsWorkerUrl from "file-loader!ace-builds/src-noconflict/javascript_worker";
843
      // ace.config.setModuleUrl("ace/mode/javascript_worker", jsWorkerUrl)
844
      //
845
      // Note: some lint disabling may be needed for the above
846

847
      // // @ts-ignore
848
      // this.createWorker = function (session) {
849
      //   const worker = new WorkerClient(["ace"], "ace/mode/javascript_worker", "JavaScriptWorker");
850
      //   worker.attachToDocument(session.getDocument())
851
      //
852
      //   // @ts-ignore
853
      //   worker.on('annotate', function (results) {
854
      //     session.setAnnotations(results.data)
855
      //   })
856
      //
857
      //   worker.on('terminate', function () {
858
      //     session.clearAnnotations()
859
      //   })
860
      //
861
      //   return worker
862
      // }
863

864
      // @ts-ignore
865
      this.$id = 'ace/mode/source' + name
3✔
866
    }).call(Mode.prototype)
867

868
    exports.Mode = Mode
3✔
869
  }
870
  // @ts-ignore
871
  ace.define(
7✔
872
    'ace/mode/source' + name,
873
    [
874
      'require',
875
      'exports',
876
      'module',
877
      'ace/lib/oop',
878
      'ace/mode/text',
879
      'ace/mode/source_highlight_rules1',
880
      'ace/mode/matching_brace_outdent',
881
      'ace/worker/worker_client',
882
      'ace/mode/behaviour/cstyle',
883
      'ace/mode/folding/cstyle'
884
    ],
885
    _Mode
886
  )
887
}
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