@uiw/react-md-editor 3.20.9 → 3.20.10

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/dist/mdeditor.js CHANGED
@@ -17389,6 +17389,8 @@ __webpack_require__.d(__webpack_exports__, {
17389
17389
  "group": () => (/* reexport */ group),
17390
17390
  "hr": () => (/* reexport */ hr),
17391
17391
  "image": () => (/* reexport */ commands_image_image),
17392
+ "insertAtLineStart": () => (/* reexport */ insertAtLineStart),
17393
+ "insertTextAtPosition": () => (/* reexport */ insertTextAtPosition),
17392
17394
  "italic": () => (/* reexport */ italic),
17393
17395
  "link": () => (/* reexport */ commands_link_link),
17394
17396
  "orderedListCommand": () => (/* reexport */ orderedListCommand),
@@ -33434,17 +33436,19 @@ ReactMarkdown.propTypes = {
33434
33436
 
33435
33437
  ;// CONCATENATED MODULE: ../node_modules/micromark-extension-gfm-autolink-literal/lib/syntax.js
33436
33438
  /**
33437
- * @typedef {import('micromark-util-types').Extension} Extension
33439
+ * @typedef {import('micromark-util-types').Code} Code
33438
33440
  * @typedef {import('micromark-util-types').ConstructRecord} ConstructRecord
33439
- * @typedef {import('micromark-util-types').Tokenizer} Tokenizer
33441
+ * @typedef {import('micromark-util-types').Event} Event
33442
+ * @typedef {import('micromark-util-types').Extension} Extension
33440
33443
  * @typedef {import('micromark-util-types').Previous} Previous
33441
33444
  * @typedef {import('micromark-util-types').State} State
33442
- * @typedef {import('micromark-util-types').Event} Event
33443
- * @typedef {import('micromark-util-types').Code} Code
33445
+ * @typedef {import('micromark-util-types').TokenizeContext} TokenizeContext
33446
+ * @typedef {import('micromark-util-types').Tokenizer} Tokenizer
33444
33447
  */
33445
33448
 
33446
- const www = {
33447
- tokenize: tokenizeWww,
33449
+
33450
+ const wwwPrefix = {
33451
+ tokenize: tokenizeWwwPrefix,
33448
33452
  partial: true
33449
33453
  }
33450
33454
  const domain = {
@@ -33455,546 +33459,886 @@ const syntax_path = {
33455
33459
  tokenize: tokenizePath,
33456
33460
  partial: true
33457
33461
  }
33458
- const punctuation = {
33459
- tokenize: tokenizePunctuation,
33462
+ const trail = {
33463
+ tokenize: tokenizeTrail,
33460
33464
  partial: true
33461
33465
  }
33462
- const namedCharacterReference = {
33463
- tokenize: tokenizeNamedCharacterReference,
33466
+ const emailDomainDotTrail = {
33467
+ tokenize: tokenizeEmailDomainDotTrail,
33464
33468
  partial: true
33465
33469
  }
33466
33470
  const wwwAutolink = {
33467
33471
  tokenize: tokenizeWwwAutolink,
33468
33472
  previous: previousWww
33469
33473
  }
33470
- const httpAutolink = {
33471
- tokenize: tokenizeHttpAutolink,
33472
- previous: previousHttp
33474
+ const protocolAutolink = {
33475
+ tokenize: tokenizeProtocolAutolink,
33476
+ previous: previousProtocol
33473
33477
  }
33474
33478
  const emailAutolink = {
33475
33479
  tokenize: tokenizeEmailAutolink,
33476
33480
  previous: previousEmail
33477
33481
  }
33478
- /** @type {ConstructRecord} */
33479
33482
 
33483
+ /** @type {ConstructRecord} */
33480
33484
  const syntax_text = {}
33481
- /** @type {Extension} */
33482
33485
 
33486
+ // To do: next major: expose functions that yields extension.
33487
+
33488
+ /**
33489
+ * Extension for `micromark` that can be passed in `extensions` to enable GFM
33490
+ * autolink literal syntax.
33491
+ *
33492
+ * @type {Extension}
33493
+ */
33483
33494
  const gfmAutolinkLiteral = {
33484
33495
  text: syntax_text
33485
33496
  }
33486
- let syntax_code = 48 // Add alphanumerics.
33497
+ let syntax_code = 48
33487
33498
 
33499
+ // Add alphanumerics.
33488
33500
  while (syntax_code < 123) {
33489
33501
  syntax_text[syntax_code] = emailAutolink
33490
33502
  syntax_code++
33491
33503
  if (syntax_code === 58) syntax_code = 65
33492
33504
  else if (syntax_code === 91) syntax_code = 97
33493
33505
  }
33494
-
33495
33506
  syntax_text[43] = emailAutolink
33496
33507
  syntax_text[45] = emailAutolink
33497
33508
  syntax_text[46] = emailAutolink
33498
33509
  syntax_text[95] = emailAutolink
33499
- syntax_text[72] = [emailAutolink, httpAutolink]
33500
- syntax_text[104] = [emailAutolink, httpAutolink]
33510
+ syntax_text[72] = [emailAutolink, protocolAutolink]
33511
+ syntax_text[104] = [emailAutolink, protocolAutolink]
33501
33512
  syntax_text[87] = [emailAutolink, wwwAutolink]
33502
33513
  syntax_text[119] = [emailAutolink, wwwAutolink]
33503
- /** @type {Tokenizer} */
33504
33514
 
33515
+ // To do: perform email autolink literals on events, afterwards.
33516
+ // That’s where `markdown-rs` and `cmark-gfm` perform it.
33517
+ // It should look for `@`, then for atext backwards, and then for a label
33518
+ // forwards.
33519
+ // To do: `mailto:`, `xmpp:` protocol as prefix.
33520
+
33521
+ /**
33522
+ * Email autolink literal.
33523
+ *
33524
+ * ```markdown
33525
+ * > | a contact@example.org b
33526
+ * ^^^^^^^^^^^^^^^^^^^
33527
+ * ```
33528
+ *
33529
+ * @this {TokenizeContext}
33530
+ * @type {Tokenizer}
33531
+ */
33505
33532
  function tokenizeEmailAutolink(effects, ok, nok) {
33506
33533
  const self = this
33534
+ /** @type {boolean | undefined} */
33535
+ let dot
33507
33536
  /** @type {boolean} */
33508
-
33509
- let hasDot
33510
- /** @type {boolean|undefined} */
33511
-
33512
- let hasDigitInLastSegment
33537
+ let data
33513
33538
  return start
33514
- /** @type {State} */
33515
33539
 
33540
+ /**
33541
+ * Start of email autolink literal.
33542
+ *
33543
+ * ```markdown
33544
+ * > | a contact@example.org b
33545
+ * ^
33546
+ * ```
33547
+ *
33548
+ * @type {State}
33549
+ */
33516
33550
  function start(code) {
33517
33551
  if (
33518
33552
  !gfmAtext(code) ||
33519
- !previousEmail(self.previous) ||
33553
+ !previousEmail.call(self, self.previous) ||
33520
33554
  previousUnbalanced(self.events)
33521
33555
  ) {
33522
33556
  return nok(code)
33523
33557
  }
33524
-
33525
33558
  effects.enter('literalAutolink')
33526
33559
  effects.enter('literalAutolinkEmail')
33527
33560
  return atext(code)
33528
33561
  }
33529
- /** @type {State} */
33530
33562
 
33563
+ /**
33564
+ * In email atext.
33565
+ *
33566
+ * ```markdown
33567
+ * > | a contact@example.org b
33568
+ * ^
33569
+ * ```
33570
+ *
33571
+ * @type {State}
33572
+ */
33531
33573
  function atext(code) {
33532
33574
  if (gfmAtext(code)) {
33533
33575
  effects.consume(code)
33534
33576
  return atext
33535
33577
  }
33536
-
33537
33578
  if (code === 64) {
33538
33579
  effects.consume(code)
33539
- return label
33580
+ return emailDomain
33540
33581
  }
33541
-
33542
33582
  return nok(code)
33543
33583
  }
33544
- /** @type {State} */
33545
33584
 
33546
- function label(code) {
33585
+ /**
33586
+ * In email domain.
33587
+ *
33588
+ * The reference code is a bit overly complex as it handles the `@`, of which
33589
+ * there may be just one.
33590
+ * Source: <https://github.com/github/cmark-gfm/blob/ef1cfcb/extensions/autolink.c#L318>
33591
+ *
33592
+ * ```markdown
33593
+ * > | a contact@example.org b
33594
+ * ^
33595
+ * ```
33596
+ *
33597
+ * @type {State}
33598
+ */
33599
+ function emailDomain(code) {
33600
+ // Dot followed by alphanumerical (not `-` or `_`).
33547
33601
  if (code === 46) {
33548
- return effects.check(punctuation, done, dotContinuation)(code)
33549
- }
33550
-
33551
- if (code === 45 || code === 95) {
33552
- return effects.check(punctuation, nok, dashOrUnderscoreContinuation)(code)
33602
+ return effects.check(
33603
+ emailDomainDotTrail,
33604
+ emailDomainAfter,
33605
+ emailDomainDot
33606
+ )(code)
33553
33607
  }
33554
33608
 
33555
- if (asciiAlphanumeric(code)) {
33556
- if (!hasDigitInLastSegment && asciiDigit(code)) {
33557
- hasDigitInLastSegment = true
33558
- }
33559
-
33609
+ // Alphanumerical, `-`, and `_`.
33610
+ if (code === 45 || code === 95 || asciiAlphanumeric(code)) {
33611
+ data = true
33560
33612
  effects.consume(code)
33561
- return label
33613
+ return emailDomain
33562
33614
  }
33563
33615
 
33564
- return done(code)
33565
- }
33566
- /** @type {State} */
33616
+ // To do: `/` if xmpp.
33567
33617
 
33568
- function dotContinuation(code) {
33569
- effects.consume(code)
33570
- hasDot = true
33571
- hasDigitInLastSegment = undefined
33572
- return label
33618
+ // Note: normally we’d truncate trailing punctuation from the link.
33619
+ // However, email autolink literals cannot contain any of those markers,
33620
+ // except for `.`, but that can only occur if it isn’t trailing.
33621
+ // So we can ignore truncating!
33622
+ return emailDomainAfter(code)
33573
33623
  }
33574
- /** @type {State} */
33575
33624
 
33576
- function dashOrUnderscoreContinuation(code) {
33625
+ /**
33626
+ * In email domain, on dot that is not a trail.
33627
+ *
33628
+ * ```markdown
33629
+ * > | a contact@example.org b
33630
+ * ^
33631
+ * ```
33632
+ *
33633
+ * @type {State}
33634
+ */
33635
+ function emailDomainDot(code) {
33577
33636
  effects.consume(code)
33578
- return afterDashOrUnderscore
33579
- }
33580
- /** @type {State} */
33581
-
33582
- function afterDashOrUnderscore(code) {
33583
- if (code === 46) {
33584
- return effects.check(punctuation, nok, dotContinuation)(code)
33585
- }
33586
-
33587
- return label(code)
33637
+ dot = true
33638
+ return emailDomain
33588
33639
  }
33589
- /** @type {State} */
33590
33640
 
33591
- function done(code) {
33592
- if (hasDot && !hasDigitInLastSegment) {
33641
+ /**
33642
+ * After email domain.
33643
+ *
33644
+ * ```markdown
33645
+ * > | a contact@example.org b
33646
+ * ^
33647
+ * ```
33648
+ *
33649
+ * @type {State}
33650
+ */
33651
+ function emailDomainAfter(code) {
33652
+ // Domain must not be empty, must include a dot, and must end in alphabetical.
33653
+ // Source: <https://github.com/github/cmark-gfm/blob/ef1cfcb/extensions/autolink.c#L332>.
33654
+ if (data && dot && asciiAlpha(self.previous)) {
33593
33655
  effects.exit('literalAutolinkEmail')
33594
33656
  effects.exit('literalAutolink')
33595
33657
  return ok(code)
33596
33658
  }
33597
-
33598
33659
  return nok(code)
33599
33660
  }
33600
33661
  }
33601
- /** @type {Tokenizer} */
33602
33662
 
33663
+ /**
33664
+ * `www` autolink literal.
33665
+ *
33666
+ * ```markdown
33667
+ * > | a www.example.org b
33668
+ * ^^^^^^^^^^^^^^^
33669
+ * ```
33670
+ *
33671
+ * @this {TokenizeContext}
33672
+ * @type {Tokenizer}
33673
+ */
33603
33674
  function tokenizeWwwAutolink(effects, ok, nok) {
33604
33675
  const self = this
33605
- return start
33606
- /** @type {State} */
33676
+ return wwwStart
33607
33677
 
33608
- function start(code) {
33678
+ /**
33679
+ * Start of www autolink literal.
33680
+ *
33681
+ * ```markdown
33682
+ * > | www.example.com/a?b#c
33683
+ * ^
33684
+ * ```
33685
+ *
33686
+ * @type {State}
33687
+ */
33688
+ function wwwStart(code) {
33609
33689
  if (
33610
33690
  (code !== 87 && code !== 119) ||
33611
- !previousWww(self.previous) ||
33691
+ !previousWww.call(self, self.previous) ||
33612
33692
  previousUnbalanced(self.events)
33613
33693
  ) {
33614
33694
  return nok(code)
33615
33695
  }
33616
-
33617
33696
  effects.enter('literalAutolink')
33618
- effects.enter('literalAutolinkWww') // For `www.` we check instead of attempt, because when it matches, GH
33619
- // treats it as part of a domain (yes, it says a valid domain must come
33620
- // after `www.`, but that’s not how it’s implemented by them).
33621
-
33697
+ effects.enter('literalAutolinkWww')
33698
+ // Note: we *check*, so we can discard the `www.` we parsed.
33699
+ // If it worked, we consider it as a part of the domain.
33622
33700
  return effects.check(
33623
- www,
33624
- effects.attempt(domain, effects.attempt(syntax_path, done), nok),
33701
+ wwwPrefix,
33702
+ effects.attempt(domain, effects.attempt(syntax_path, wwwAfter), nok),
33625
33703
  nok
33626
33704
  )(code)
33627
33705
  }
33628
- /** @type {State} */
33629
33706
 
33630
- function done(code) {
33707
+ /**
33708
+ * After a www autolink literal.
33709
+ *
33710
+ * ```markdown
33711
+ * > | www.example.com/a?b#c
33712
+ * ^
33713
+ * ```
33714
+ *
33715
+ * @type {State}
33716
+ */
33717
+ function wwwAfter(code) {
33631
33718
  effects.exit('literalAutolinkWww')
33632
33719
  effects.exit('literalAutolink')
33633
33720
  return ok(code)
33634
33721
  }
33635
33722
  }
33636
- /** @type {Tokenizer} */
33637
33723
 
33638
- function tokenizeHttpAutolink(effects, ok, nok) {
33724
+ /**
33725
+ * Protocol autolink literal.
33726
+ *
33727
+ * ```markdown
33728
+ * > | a https://example.org b
33729
+ * ^^^^^^^^^^^^^^^^^^^
33730
+ * ```
33731
+ *
33732
+ * @this {TokenizeContext}
33733
+ * @type {Tokenizer}
33734
+ */
33735
+ function tokenizeProtocolAutolink(effects, ok, nok) {
33639
33736
  const self = this
33640
- return start
33641
- /** @type {State} */
33737
+ let buffer = ''
33738
+ let seen = false
33739
+ return protocolStart
33642
33740
 
33643
- function start(code) {
33741
+ /**
33742
+ * Start of protocol autolink literal.
33743
+ *
33744
+ * ```markdown
33745
+ * > | https://example.com/a?b#c
33746
+ * ^
33747
+ * ```
33748
+ *
33749
+ * @type {State}
33750
+ */
33751
+ function protocolStart(code) {
33644
33752
  if (
33645
- (code !== 72 && code !== 104) ||
33646
- !previousHttp(self.previous) ||
33647
- previousUnbalanced(self.events)
33753
+ (code === 72 || code === 104) &&
33754
+ previousProtocol.call(self, self.previous) &&
33755
+ !previousUnbalanced(self.events)
33648
33756
  ) {
33649
- return nok(code)
33650
- }
33651
-
33652
- effects.enter('literalAutolink')
33653
- effects.enter('literalAutolinkHttp')
33654
- effects.consume(code)
33655
- return t1
33656
- }
33657
- /** @type {State} */
33658
-
33659
- function t1(code) {
33660
- if (code === 84 || code === 116) {
33757
+ effects.enter('literalAutolink')
33758
+ effects.enter('literalAutolinkHttp')
33759
+ buffer += String.fromCodePoint(code)
33661
33760
  effects.consume(code)
33662
- return t2
33761
+ return protocolPrefixInside
33663
33762
  }
33664
-
33665
- return nok(code)
33666
- }
33667
- /** @type {State} */
33668
-
33669
- function t2(code) {
33670
- if (code === 84 || code === 116) {
33671
- effects.consume(code)
33672
- return p
33673
- }
33674
-
33675
33763
  return nok(code)
33676
33764
  }
33677
- /** @type {State} */
33678
-
33679
- function p(code) {
33680
- if (code === 80 || code === 112) {
33681
- effects.consume(code)
33682
- return s
33683
- }
33684
-
33685
- return nok(code)
33686
- }
33687
- /** @type {State} */
33688
33765
 
33689
- function s(code) {
33690
- if (code === 83 || code === 115) {
33766
+ /**
33767
+ * In protocol.
33768
+ *
33769
+ * ```markdown
33770
+ * > | https://example.com/a?b#c
33771
+ * ^^^^^
33772
+ * ```
33773
+ *
33774
+ * @type {State}
33775
+ */
33776
+ function protocolPrefixInside(code) {
33777
+ // `5` is size of `https`
33778
+ if (asciiAlpha(code) && buffer.length < 5) {
33779
+ buffer += String.fromCodePoint(code)
33691
33780
  effects.consume(code)
33692
- return colon
33781
+ return protocolPrefixInside
33693
33782
  }
33694
-
33695
- return colon(code)
33696
- }
33697
- /** @type {State} */
33698
-
33699
- function colon(code) {
33700
33783
  if (code === 58) {
33701
- effects.consume(code)
33702
- return slash1
33703
- }
33704
-
33705
- return nok(code)
33706
- }
33707
- /** @type {State} */
33708
-
33709
- function slash1(code) {
33710
- if (code === 47) {
33711
- effects.consume(code)
33712
- return slash2
33784
+ const protocol = buffer.toLowerCase()
33785
+ if (protocol === 'http' || protocol === 'https') {
33786
+ effects.consume(code)
33787
+ return protocolSlashesInside
33788
+ }
33713
33789
  }
33714
-
33715
33790
  return nok(code)
33716
33791
  }
33717
- /** @type {State} */
33718
33792
 
33719
- function slash2(code) {
33793
+ /**
33794
+ * In slashes.
33795
+ *
33796
+ * ```markdown
33797
+ * > | https://example.com/a?b#c
33798
+ * ^^
33799
+ * ```
33800
+ *
33801
+ * @type {State}
33802
+ */
33803
+ function protocolSlashesInside(code) {
33720
33804
  if (code === 47) {
33721
33805
  effects.consume(code)
33722
- return after
33806
+ if (seen) {
33807
+ return afterProtocol
33808
+ }
33809
+ seen = true
33810
+ return protocolSlashesInside
33723
33811
  }
33724
-
33725
33812
  return nok(code)
33726
33813
  }
33727
- /** @type {State} */
33728
33814
 
33729
- function after(code) {
33815
+ /**
33816
+ * After protocol, before domain.
33817
+ *
33818
+ * ```markdown
33819
+ * > | https://example.com/a?b#c
33820
+ * ^
33821
+ * ```
33822
+ *
33823
+ * @type {State}
33824
+ */
33825
+ function afterProtocol(code) {
33826
+ // To do: this is different from `markdown-rs`:
33827
+ // https://github.com/wooorm/markdown-rs/blob/b3a921c761309ae00a51fe348d8a43adbc54b518/src/construct/gfm_autolink_literal.rs#L172-L182
33730
33828
  return code === null ||
33731
33829
  asciiControl(code) ||
33830
+ markdownLineEndingOrSpace(code) ||
33732
33831
  unicodeWhitespace(code) ||
33733
33832
  unicodePunctuation(code)
33734
33833
  ? nok(code)
33735
- : effects.attempt(domain, effects.attempt(syntax_path, done), nok)(code)
33834
+ : effects.attempt(domain, effects.attempt(syntax_path, protocolAfter), nok)(code)
33736
33835
  }
33737
- /** @type {State} */
33738
33836
 
33739
- function done(code) {
33837
+ /**
33838
+ * After a protocol autolink literal.
33839
+ *
33840
+ * ```markdown
33841
+ * > | https://example.com/a?b#c
33842
+ * ^
33843
+ * ```
33844
+ *
33845
+ * @type {State}
33846
+ */
33847
+ function protocolAfter(code) {
33740
33848
  effects.exit('literalAutolinkHttp')
33741
33849
  effects.exit('literalAutolink')
33742
33850
  return ok(code)
33743
33851
  }
33744
33852
  }
33745
- /** @type {Tokenizer} */
33746
-
33747
- function tokenizeWww(effects, ok, nok) {
33748
- return start
33749
- /** @type {State} */
33750
33853
 
33751
- function start(code) {
33752
- effects.consume(code)
33753
- return w2
33754
- }
33755
- /** @type {State} */
33854
+ /**
33855
+ * `www` prefix.
33856
+ *
33857
+ * ```markdown
33858
+ * > | a www.example.org b
33859
+ * ^^^^
33860
+ * ```
33861
+ *
33862
+ * @this {TokenizeContext}
33863
+ * @type {Tokenizer}
33864
+ */
33865
+ function tokenizeWwwPrefix(effects, ok, nok) {
33866
+ let size = 0
33867
+ return wwwPrefixInside
33756
33868
 
33757
- function w2(code) {
33758
- if (code === 87 || code === 119) {
33869
+ /**
33870
+ * In www prefix.
33871
+ *
33872
+ * ```markdown
33873
+ * > | www.example.com
33874
+ * ^^^^
33875
+ * ```
33876
+ *
33877
+ * @type {State}
33878
+ */
33879
+ function wwwPrefixInside(code) {
33880
+ if ((code === 87 || code === 119) && size < 3) {
33881
+ size++
33759
33882
  effects.consume(code)
33760
- return w3
33883
+ return wwwPrefixInside
33884
+ }
33885
+ if (code === 46 && size === 3) {
33886
+ effects.consume(code)
33887
+ return wwwPrefixAfter
33761
33888
  }
33762
-
33763
33889
  return nok(code)
33764
33890
  }
33765
- /** @type {State} */
33766
-
33767
- function w3(code) {
33768
- if (code === 87 || code === 119) {
33769
- effects.consume(code)
33770
- return dot
33771
- }
33772
-
33773
- return nok(code)
33774
- }
33775
- /** @type {State} */
33776
-
33777
- function dot(code) {
33778
- if (code === 46) {
33779
- effects.consume(code)
33780
- return after
33781
- }
33782
-
33783
- return nok(code)
33784
- }
33785
- /** @type {State} */
33786
33891
 
33787
- function after(code) {
33788
- return code === null || markdownLineEnding(code) ? nok(code) : ok(code)
33892
+ /**
33893
+ * After www prefix.
33894
+ *
33895
+ * ```markdown
33896
+ * > | www.example.com
33897
+ * ^
33898
+ * ```
33899
+ *
33900
+ * @type {State}
33901
+ */
33902
+ function wwwPrefixAfter(code) {
33903
+ // If there is *anything*, we can link.
33904
+ return code === null ? nok(code) : ok(code)
33789
33905
  }
33790
33906
  }
33791
- /** @type {Tokenizer} */
33792
33907
 
33908
+ /**
33909
+ * Domain.
33910
+ *
33911
+ * ```markdown
33912
+ * > | a https://example.org b
33913
+ * ^^^^^^^^^^^
33914
+ * ```
33915
+ *
33916
+ * @this {TokenizeContext}
33917
+ * @type {Tokenizer}
33918
+ */
33793
33919
  function tokenizeDomain(effects, ok, nok) {
33794
- /** @type {boolean|undefined} */
33795
- let hasUnderscoreInLastSegment
33796
- /** @type {boolean|undefined} */
33797
-
33798
- let hasUnderscoreInLastLastSegment
33799
- return domain
33800
- /** @type {State} */
33920
+ /** @type {boolean | undefined} */
33921
+ let underscoreInLastSegment
33922
+ /** @type {boolean | undefined} */
33923
+ let underscoreInLastLastSegment
33924
+ /** @type {boolean | undefined} */
33925
+ let seen
33926
+ return domainInside
33801
33927
 
33802
- function domain(code) {
33803
- if (code === 38) {
33804
- return effects.check(
33805
- namedCharacterReference,
33806
- done,
33807
- punctuationContinuation
33808
- )(code)
33928
+ /**
33929
+ * In domain.
33930
+ *
33931
+ * ```markdown
33932
+ * > | https://example.com/a
33933
+ * ^^^^^^^^^^^
33934
+ * ```
33935
+ *
33936
+ * @type {State}
33937
+ */
33938
+ function domainInside(code) {
33939
+ // Check whether this marker, which is a trailing punctuation
33940
+ // marker, optionally followed by more trailing markers, and then
33941
+ // followed by an end.
33942
+ if (code === 46 || code === 95) {
33943
+ return effects.check(trail, domainAfter, domainAtPunctuation)(code)
33809
33944
  }
33810
33945
 
33811
- if (code === 46 || code === 95) {
33812
- return effects.check(punctuation, done, punctuationContinuation)(code)
33813
- } // GH documents that only alphanumerics (other than `-`, `.`, and `_`) can
33946
+ // GH documents that only alphanumerics (other than `-`, `.`, and `_`) can
33814
33947
  // occur, which sounds like ASCII only, but they also support `www.點看.com`,
33815
33948
  // so that’s Unicode.
33816
33949
  // Instead of some new production for Unicode alphanumerics, markdown
33817
33950
  // already has that for Unicode punctuation and whitespace, so use those.
33818
-
33951
+ // Source: <https://github.com/github/cmark-gfm/blob/ef1cfcb/extensions/autolink.c#L12>.
33819
33952
  if (
33820
33953
  code === null ||
33821
- asciiControl(code) ||
33954
+ markdownLineEndingOrSpace(code) ||
33822
33955
  unicodeWhitespace(code) ||
33823
33956
  (code !== 45 && unicodePunctuation(code))
33824
33957
  ) {
33825
- return done(code)
33958
+ return domainAfter(code)
33826
33959
  }
33827
-
33960
+ seen = true
33828
33961
  effects.consume(code)
33829
- return domain
33962
+ return domainInside
33830
33963
  }
33831
- /** @type {State} */
33832
33964
 
33833
- function punctuationContinuation(code) {
33834
- if (code === 46) {
33835
- hasUnderscoreInLastLastSegment = hasUnderscoreInLastSegment
33836
- hasUnderscoreInLastSegment = undefined
33837
- effects.consume(code)
33838
- return domain
33965
+ /**
33966
+ * In domain, at potential trailing punctuation, that was not trailing.
33967
+ *
33968
+ * ```markdown
33969
+ * > | https://example.com
33970
+ * ^
33971
+ * ```
33972
+ *
33973
+ * @type {State}
33974
+ */
33975
+ function domainAtPunctuation(code) {
33976
+ // There is an underscore in the last segment of the domain
33977
+ if (code === 95) {
33978
+ underscoreInLastSegment = true
33979
+ }
33980
+ // Otherwise, it’s a `.`: save the last segment underscore in the
33981
+ // penultimate segment slot.
33982
+ else {
33983
+ underscoreInLastLastSegment = underscoreInLastSegment
33984
+ underscoreInLastSegment = undefined
33839
33985
  }
33840
-
33841
- if (code === 95) hasUnderscoreInLastSegment = true
33842
33986
  effects.consume(code)
33843
- return domain
33987
+ return domainInside
33844
33988
  }
33845
- /** @type {State} */
33846
33989
 
33847
- function done(code) {
33848
- if (!hasUnderscoreInLastLastSegment && !hasUnderscoreInLastSegment) {
33849
- return ok(code)
33990
+ /**
33991
+ * After domain.
33992
+ *
33993
+ * ```markdown
33994
+ * > | https://example.com/a
33995
+ * ^
33996
+ * ```
33997
+ *
33998
+ * @type {State} */
33999
+ function domainAfter(code) {
34000
+ // Note: that’s GH says a dot is needed, but it’s not true:
34001
+ // <https://github.com/github/cmark-gfm/issues/279>
34002
+ if (underscoreInLastLastSegment || underscoreInLastSegment || !seen) {
34003
+ return nok(code)
33850
34004
  }
33851
-
33852
- return nok(code)
34005
+ return ok(code)
33853
34006
  }
33854
34007
  }
33855
- /** @type {Tokenizer} */
33856
34008
 
34009
+ /**
34010
+ * Path.
34011
+ *
34012
+ * ```markdown
34013
+ * > | a https://example.org/stuff b
34014
+ * ^^^^^^
34015
+ * ```
34016
+ *
34017
+ * @this {TokenizeContext}
34018
+ * @type {Tokenizer}
34019
+ */
33857
34020
  function tokenizePath(effects, ok) {
33858
- let balance = 0
33859
- return inPath
33860
- /** @type {State} */
33861
-
33862
- function inPath(code) {
33863
- if (code === 38) {
33864
- return effects.check(
33865
- namedCharacterReference,
33866
- ok,
33867
- continuedPunctuation
33868
- )(code)
33869
- }
34021
+ let sizeOpen = 0
34022
+ let sizeClose = 0
34023
+ return pathInside
33870
34024
 
34025
+ /**
34026
+ * In path.
34027
+ *
34028
+ * ```markdown
34029
+ * > | https://example.com/a
34030
+ * ^^
34031
+ * ```
34032
+ *
34033
+ * @type {State}
34034
+ */
34035
+ function pathInside(code) {
33871
34036
  if (code === 40) {
33872
- balance++
34037
+ sizeOpen++
34038
+ effects.consume(code)
34039
+ return pathInside
33873
34040
  }
33874
34041
 
33875
- if (code === 41) {
33876
- return effects.check(
33877
- punctuation,
33878
- parenAtPathEnd,
33879
- continuedPunctuation
33880
- )(code)
34042
+ // To do: `markdown-rs` also needs this.
34043
+ // If this is a paren, and there are less closings than openings,
34044
+ // we don’t check for a trail.
34045
+ if (code === 41 && sizeClose < sizeOpen) {
34046
+ return pathAtPunctuation(code)
33881
34047
  }
33882
34048
 
33883
- if (pathEnd(code)) {
33884
- return ok(code)
34049
+ // Check whether this trailing punctuation marker is optionally
34050
+ // followed by more trailing markers, and then followed
34051
+ // by an end.
34052
+ if (
34053
+ code === 33 ||
34054
+ code === 34 ||
34055
+ code === 38 ||
34056
+ code === 39 ||
34057
+ code === 41 ||
34058
+ code === 42 ||
34059
+ code === 44 ||
34060
+ code === 46 ||
34061
+ code === 58 ||
34062
+ code === 59 ||
34063
+ code === 60 ||
34064
+ code === 63 ||
34065
+ code === 93 ||
34066
+ code === 95 ||
34067
+ code === 126
34068
+ ) {
34069
+ return effects.check(trail, ok, pathAtPunctuation)(code)
33885
34070
  }
33886
-
33887
- if (trailingPunctuation(code)) {
33888
- return effects.check(punctuation, ok, continuedPunctuation)(code)
34071
+ if (
34072
+ code === null ||
34073
+ markdownLineEndingOrSpace(code) ||
34074
+ unicodeWhitespace(code)
34075
+ ) {
34076
+ return ok(code)
33889
34077
  }
33890
-
33891
34078
  effects.consume(code)
33892
- return inPath
34079
+ return pathInside
33893
34080
  }
33894
- /** @type {State} */
33895
34081
 
33896
- function continuedPunctuation(code) {
34082
+ /**
34083
+ * In path, at potential trailing punctuation, that was not trailing.
34084
+ *
34085
+ * ```markdown
34086
+ * > | https://example.com/a"b
34087
+ * ^
34088
+ * ```
34089
+ *
34090
+ * @type {State}
34091
+ */
34092
+ function pathAtPunctuation(code) {
34093
+ // Count closing parens.
34094
+ if (code === 41) {
34095
+ sizeClose++
34096
+ }
33897
34097
  effects.consume(code)
33898
- return inPath
33899
- }
33900
- /** @type {State} */
33901
-
33902
- function parenAtPathEnd(code) {
33903
- balance--
33904
- return balance < 0 ? ok(code) : continuedPunctuation(code)
34098
+ return pathInside
33905
34099
  }
33906
34100
  }
33907
- /** @type {Tokenizer} */
33908
34101
 
33909
- function tokenizeNamedCharacterReference(effects, ok, nok) {
33910
- return start
33911
- /** @type {State} */
33912
-
33913
- function start(code) {
33914
- effects.consume(code)
33915
- return inside
33916
- }
33917
- /** @type {State} */
34102
+ /**
34103
+ * Trail.
34104
+ *
34105
+ * This calls `ok` if this *is* the trail, followed by an end, which means
34106
+ * the entire trail is not part of the link.
34107
+ * It calls `nok` if this *is* part of the link.
34108
+ *
34109
+ * ```markdown
34110
+ * > | https://example.com").
34111
+ * ^^^
34112
+ * ```
34113
+ *
34114
+ * @this {TokenizeContext}
34115
+ * @type {Tokenizer}
34116
+ */
34117
+ function tokenizeTrail(effects, ok, nok) {
34118
+ return trail
33918
34119
 
33919
- function inside(code) {
33920
- if (asciiAlpha(code)) {
34120
+ /**
34121
+ * In trail of domain or path.
34122
+ *
34123
+ * ```markdown
34124
+ * > | https://example.com").
34125
+ * ^
34126
+ * ```
34127
+ *
34128
+ * @type {State}
34129
+ */
34130
+ function trail(code) {
34131
+ // Regular trailing punctuation.
34132
+ if (
34133
+ code === 33 ||
34134
+ code === 34 ||
34135
+ code === 39 ||
34136
+ code === 41 ||
34137
+ code === 42 ||
34138
+ code === 44 ||
34139
+ code === 46 ||
34140
+ code === 58 ||
34141
+ code === 59 ||
34142
+ code === 63 ||
34143
+ code === 95 ||
34144
+ code === 126
34145
+ ) {
33921
34146
  effects.consume(code)
33922
- return inside
34147
+ return trail
33923
34148
  }
33924
34149
 
33925
- if (code === 59) {
34150
+ // `&` followed by one or more alphabeticals and then a `;`, is
34151
+ // as a whole considered as trailing punctuation.
34152
+ // In all other cases, it is considered as continuation of the URL.
34153
+ if (code === 38) {
33926
34154
  effects.consume(code)
33927
- return after
34155
+ return trailCharRefStart
33928
34156
  }
33929
34157
 
34158
+ // Needed because we allow literals after `[`, as we fix:
34159
+ // <https://github.com/github/cmark-gfm/issues/278>.
34160
+ // Check that it is not followed by `(` or `[`.
34161
+ if (code === 93) {
34162
+ effects.consume(code)
34163
+ return trailBracketAfter
34164
+ }
34165
+ if (
34166
+ // `<` is an end.
34167
+ code === 60 ||
34168
+ // So is whitespace.
34169
+ code === null ||
34170
+ markdownLineEndingOrSpace(code) ||
34171
+ unicodeWhitespace(code)
34172
+ ) {
34173
+ return ok(code)
34174
+ }
33930
34175
  return nok(code)
33931
34176
  }
33932
- /** @type {State} */
33933
34177
 
33934
- function after(code) {
33935
- // If the named character reference is followed by the end of the path, it’s
33936
- // not continued punctuation.
33937
- return pathEnd(code) ? ok(code) : nok(code)
34178
+ /**
34179
+ * In trail, after `]`.
34180
+ *
34181
+ * > 👉 **Note**: this deviates from `cmark-gfm` to fix a bug.
34182
+ * > See end of <https://github.com/github/cmark-gfm/issues/278> for more.
34183
+ *
34184
+ * ```markdown
34185
+ * > | https://example.com](
34186
+ * ^
34187
+ * ```
34188
+ *
34189
+ * @type {State}
34190
+ */
34191
+ function trailBracketAfter(code) {
34192
+ // Whitespace or something that could start a resource or reference is the end.
34193
+ // Switch back to trail otherwise.
34194
+ if (
34195
+ code === null ||
34196
+ code === 40 ||
34197
+ code === 91 ||
34198
+ markdownLineEndingOrSpace(code) ||
34199
+ unicodeWhitespace(code)
34200
+ ) {
34201
+ return ok(code)
34202
+ }
34203
+ return trail(code)
34204
+ }
34205
+
34206
+ /**
34207
+ * In character-reference like trail, after `&`.
34208
+ *
34209
+ * ```markdown
34210
+ * > | https://example.com&amp;).
34211
+ * ^
34212
+ * ```
34213
+ *
34214
+ * @type {State}
34215
+ */
34216
+ function trailCharRefStart(code) {
34217
+ // When non-alpha, it’s not a trail.
34218
+ return asciiAlpha(code) ? trailCharRefInside(code) : nok(code)
34219
+ }
34220
+
34221
+ /**
34222
+ * In character-reference like trail.
34223
+ *
34224
+ * ```markdown
34225
+ * > | https://example.com&amp;).
34226
+ * ^
34227
+ * ```
34228
+ *
34229
+ * @type {State}
34230
+ */
34231
+ function trailCharRefInside(code) {
34232
+ // Switch back to trail if this is well-formed.
34233
+ if (code === 59) {
34234
+ effects.consume(code)
34235
+ return trail
34236
+ }
34237
+ if (asciiAlpha(code)) {
34238
+ effects.consume(code)
34239
+ return trailCharRefInside
34240
+ }
34241
+
34242
+ // It’s not a trail.
34243
+ return nok(code)
33938
34244
  }
33939
34245
  }
33940
- /** @type {Tokenizer} */
33941
34246
 
33942
- function tokenizePunctuation(effects, ok, nok) {
34247
+ /**
34248
+ * Dot in email domain trail.
34249
+ *
34250
+ * This calls `ok` if this *is* the trail, followed by an end, which means
34251
+ * the trail is not part of the link.
34252
+ * It calls `nok` if this *is* part of the link.
34253
+ *
34254
+ * ```markdown
34255
+ * > | contact@example.org.
34256
+ * ^
34257
+ * ```
34258
+ *
34259
+ * @this {TokenizeContext}
34260
+ * @type {Tokenizer}
34261
+ */
34262
+ function tokenizeEmailDomainDotTrail(effects, ok, nok) {
33943
34263
  return start
33944
- /** @type {State} */
33945
34264
 
34265
+ /**
34266
+ * Dot.
34267
+ *
34268
+ * ```markdown
34269
+ * > | contact@example.org.
34270
+ * ^ ^
34271
+ * ```
34272
+ *
34273
+ * @type {State}
34274
+ */
33946
34275
  function start(code) {
34276
+ // Must be dot.
33947
34277
  effects.consume(code)
33948
34278
  return after
33949
34279
  }
33950
- /** @type {State} */
33951
34280
 
34281
+ /**
34282
+ * After dot.
34283
+ *
34284
+ * ```markdown
34285
+ * > | contact@example.org.
34286
+ * ^ ^
34287
+ * ```
34288
+ *
34289
+ * @type {State}
34290
+ */
33952
34291
  function after(code) {
33953
- // Check the next.
33954
- if (trailingPunctuation(code)) {
33955
- effects.consume(code)
33956
- return after
33957
- } // If the punctuation marker is followed by the end of the path, it’s not
33958
- // continued punctuation.
33959
-
33960
- return pathEnd(code) ? ok(code) : nok(code)
34292
+ // Not a trail if alphanumeric.
34293
+ return asciiAlphanumeric(code) ? nok(code) : ok(code)
33961
34294
  }
33962
34295
  }
34296
+
33963
34297
  /**
33964
- * @param {Code} code
33965
- * @returns {boolean}
34298
+ * See:
34299
+ * <https://github.com/github/cmark-gfm/blob/ef1cfcb/extensions/autolink.c#L156>.
34300
+ *
34301
+ * @type {Previous}
33966
34302
  */
33967
-
33968
- function trailingPunctuation(code) {
34303
+ function previousWww(code) {
33969
34304
  return (
33970
- code === 33 ||
33971
- code === 34 ||
33972
- code === 39 ||
33973
- code === 41 ||
34305
+ code === null ||
34306
+ code === 40 ||
33974
34307
  code === 42 ||
33975
- code === 44 ||
33976
- code === 46 ||
33977
- code === 58 ||
33978
- code === 59 ||
33979
- code === 60 ||
33980
- code === 63 ||
33981
34308
  code === 95 ||
33982
- code === 126
34309
+ code === 91 ||
34310
+ code === 93 ||
34311
+ code === 126 ||
34312
+ markdownLineEndingOrSpace(code)
33983
34313
  )
33984
34314
  }
34315
+
33985
34316
  /**
33986
- * @param {Code} code
33987
- * @returns {boolean}
34317
+ * See:
34318
+ * <https://github.com/github/cmark-gfm/blob/ef1cfcb/extensions/autolink.c#L214>.
34319
+ *
34320
+ * @type {Previous}
33988
34321
  */
34322
+ function previousProtocol(code) {
34323
+ return !asciiAlpha(code)
34324
+ }
33989
34325
 
33990
- function pathEnd(code) {
33991
- return code === null || code === 60 || markdownLineEndingOrSpace(code)
34326
+ /**
34327
+ * @this {TokenizeContext}
34328
+ * @type {Previous}
34329
+ */
34330
+ function previousEmail(code) {
34331
+ // Do not allow a slash “inside” atext.
34332
+ // The reference code is a bit weird, but that’s what it results in.
34333
+ // Source: <https://github.com/github/cmark-gfm/blob/ef1cfcb/extensions/autolink.c#L307>.
34334
+ // Other than slash, every preceding character is allowed.
34335
+ return !(code === 47 || gfmAtext(code))
33992
34336
  }
34337
+
33993
34338
  /**
33994
34339
  * @param {Code} code
33995
34340
  * @returns {boolean}
33996
34341
  */
33997
-
33998
34342
  function gfmAtext(code) {
33999
34343
  return (
34000
34344
  code === 43 ||
@@ -34004,61 +34348,36 @@ function gfmAtext(code) {
34004
34348
  asciiAlphanumeric(code)
34005
34349
  )
34006
34350
  }
34007
- /** @type {Previous} */
34008
-
34009
- function previousWww(code) {
34010
- return (
34011
- code === null ||
34012
- code === 40 ||
34013
- code === 42 ||
34014
- code === 95 ||
34015
- code === 126 ||
34016
- markdownLineEndingOrSpace(code)
34017
- )
34018
- }
34019
- /** @type {Previous} */
34020
34351
 
34021
- function previousHttp(code) {
34022
- return code === null || !asciiAlpha(code)
34023
- }
34024
- /** @type {Previous} */
34025
-
34026
- function previousEmail(code) {
34027
- return code !== 47 && previousHttp(code)
34028
- }
34029
34352
  /**
34030
34353
  * @param {Array<Event>} events
34031
34354
  * @returns {boolean}
34032
34355
  */
34033
-
34034
34356
  function previousUnbalanced(events) {
34035
34357
  let index = events.length
34036
34358
  let result = false
34037
-
34038
34359
  while (index--) {
34039
34360
  const token = events[index][1]
34040
-
34041
34361
  if (
34042
34362
  (token.type === 'labelLink' || token.type === 'labelImage') &&
34043
34363
  !token._balanced
34044
34364
  ) {
34045
34365
  result = true
34046
34366
  break
34047
- } // @ts-expect-error If we’ve seen this token, and it was marked as not
34048
- // having any unbalanced bracket before it, we can exit.
34367
+ }
34049
34368
 
34369
+ // @ts-expect-error If we’ve seen this token, and it was marked as not
34370
+ // having any unbalanced bracket before it, we can exit.
34050
34371
  if (token._gfmAutolinkLiteralWalkedInto) {
34051
34372
  result = false
34052
34373
  break
34053
34374
  }
34054
34375
  }
34055
-
34056
34376
  if (events.length > 0 && !result) {
34057
34377
  // @ts-expect-error Mark the last token as “walked into” w/o finding
34058
34378
  // anything.
34059
34379
  events[events.length - 1][1]._gfmAutolinkLiteralWalkedInto = true
34060
34380
  }
34061
-
34062
34381
  return result
34063
34382
  }
34064
34383