index.js 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. /**
  2. * @typedef {import('micromark-util-types').Effects} Effects
  3. * @typedef {import('micromark-util-types').State} State
  4. * @typedef {import('micromark-util-types').TokenType} TokenType
  5. */
  6. import {markdownSpace} from 'micromark-util-character'
  7. // To do: implement `spaceOrTab`, `spaceOrTabMinMax`, `spaceOrTabWithOptions`.
  8. /**
  9. * Parse spaces and tabs.
  10. *
  11. * There is no `nok` parameter:
  12. *
  13. * * spaces in markdown are often optional, in which case this factory can be
  14. * used and `ok` will be switched to whether spaces were found or not
  15. * * one line ending or space can be detected with `markdownSpace(code)` right
  16. * before using `factorySpace`
  17. *
  18. * ###### Examples
  19. *
  20. * Where `␉` represents a tab (plus how much it expands) and `␠` represents a
  21. * single space.
  22. *
  23. * ```markdown
  24. * ␉
  25. * ␠␠␠␠
  26. * ␉␠
  27. * ```
  28. *
  29. * @param {Effects} effects
  30. * Context.
  31. * @param {State} ok
  32. * State switched to when successful.
  33. * @param {TokenType} type
  34. * Type (`' \t'`).
  35. * @param {number | undefined} [max=Infinity]
  36. * Max (exclusive).
  37. * @returns {State}
  38. * Start state.
  39. */
  40. export function factorySpace(effects, ok, type, max) {
  41. const limit = max ? max - 1 : Number.POSITIVE_INFINITY
  42. let size = 0
  43. return start
  44. /** @type {State} */
  45. function start(code) {
  46. if (markdownSpace(code)) {
  47. effects.enter(type)
  48. return prefix(code)
  49. }
  50. return ok(code)
  51. }
  52. /** @type {State} */
  53. function prefix(code) {
  54. if (markdownSpace(code) && size++ < limit) {
  55. effects.consume(code)
  56. return prefix
  57. }
  58. effects.exit(type)
  59. return ok(code)
  60. }
  61. }