index.js 1.5 KB

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