getNextKeyDef.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.getNextKeyDef = getNextKeyDef;
  6. var bracketDict;
  7. (function (bracketDict) {
  8. bracketDict["{"] = "}";
  9. bracketDict["["] = "]";
  10. })(bracketDict || (bracketDict = {}));
  11. var legacyModifiers;
  12. (function (legacyModifiers) {
  13. legacyModifiers["alt"] = "alt";
  14. legacyModifiers["ctrl"] = "ctrl";
  15. legacyModifiers["meta"] = "meta";
  16. legacyModifiers["shift"] = "shift";
  17. })(legacyModifiers || (legacyModifiers = {}));
  18. var legacyKeyMap;
  19. /**
  20. * Get the next key from keyMap
  21. *
  22. * Keys can be referenced by `{key}` or `{special}` as well as physical locations per `[code]`.
  23. * Everything else will be interpreted as a typed character - e.g. `a`.
  24. * Brackets `{` and `[` can be escaped by doubling - e.g. `foo[[bar` translates to `foo[bar`.
  25. * Keeping the key pressed can be written as `{key>}`.
  26. * When keeping the key pressed you can choose how long (how many keydown and keypress) the key is pressed `{key>3}`.
  27. * You can then release the key per `{key>3/}` or keep it pressed and continue with the next key.
  28. * Modifiers like `{shift}` imply being kept pressed. This can be turned of per `{shift/}`.
  29. */
  30. (function (legacyKeyMap) {
  31. legacyKeyMap["ctrl"] = "Control";
  32. legacyKeyMap["del"] = "Delete";
  33. legacyKeyMap["esc"] = "Escape";
  34. legacyKeyMap["space"] = " ";
  35. })(legacyKeyMap || (legacyKeyMap = {}));
  36. function getNextKeyDef(text, options) {
  37. var _options$keyboardMap$;
  38. const {
  39. type,
  40. descriptor,
  41. consumedLength,
  42. releasePrevious,
  43. releaseSelf,
  44. repeat
  45. } = readNextDescriptor(text);
  46. const keyDef = (_options$keyboardMap$ = options.keyboardMap.find(def => {
  47. if (type === '[') {
  48. var _def$code;
  49. return ((_def$code = def.code) == null ? void 0 : _def$code.toLowerCase()) === descriptor.toLowerCase();
  50. } else if (type === '{') {
  51. var _def$key;
  52. const key = mapLegacyKey(descriptor);
  53. return ((_def$key = def.key) == null ? void 0 : _def$key.toLowerCase()) === key.toLowerCase();
  54. }
  55. return def.key === descriptor;
  56. })) != null ? _options$keyboardMap$ : {
  57. key: 'Unknown',
  58. code: 'Unknown',
  59. [type === '[' ? 'code' : 'key']: descriptor
  60. };
  61. return {
  62. keyDef,
  63. consumedLength,
  64. releasePrevious,
  65. releaseSelf,
  66. repeat
  67. };
  68. }
  69. function readNextDescriptor(text) {
  70. let pos = 0;
  71. const startBracket = text[pos] in bracketDict ? text[pos] : '';
  72. pos += startBracket.length; // `foo{{bar` is an escaped char at position 3,
  73. // but `foo{{{>5}bar` should be treated as `{` pressed down for 5 keydowns.
  74. const startBracketRepeated = startBracket ? text.match(new RegExp(`^\\${startBracket}+`))[0].length : 0;
  75. const isEscapedChar = startBracketRepeated === 2 || startBracket === '{' && startBracketRepeated > 3;
  76. const type = isEscapedChar ? '' : startBracket;
  77. return {
  78. type,
  79. ...(type === '' ? readPrintableChar(text, pos) : readTag(text, pos, type))
  80. };
  81. }
  82. function readPrintableChar(text, pos) {
  83. const descriptor = text[pos];
  84. assertDescriptor(descriptor, text, pos);
  85. pos += descriptor.length;
  86. return {
  87. consumedLength: pos,
  88. descriptor,
  89. releasePrevious: false,
  90. releaseSelf: true,
  91. repeat: 1
  92. };
  93. }
  94. function readTag(text, pos, startBracket) {
  95. var _text$slice$match, _text$slice$match$, _text$slice$match2;
  96. const releasePreviousModifier = text[pos] === '/' ? '/' : '';
  97. pos += releasePreviousModifier.length;
  98. const descriptor = (_text$slice$match = text.slice(pos).match(/^\w+/)) == null ? void 0 : _text$slice$match[0];
  99. assertDescriptor(descriptor, text, pos);
  100. pos += descriptor.length;
  101. const repeatModifier = (_text$slice$match$ = (_text$slice$match2 = text.slice(pos).match(/^>\d+/)) == null ? void 0 : _text$slice$match2[0]) != null ? _text$slice$match$ : '';
  102. pos += repeatModifier.length;
  103. const releaseSelfModifier = text[pos] === '/' || !repeatModifier && text[pos] === '>' ? text[pos] : '';
  104. pos += releaseSelfModifier.length;
  105. const expectedEndBracket = bracketDict[startBracket];
  106. const endBracket = text[pos] === expectedEndBracket ? expectedEndBracket : '';
  107. if (!endBracket) {
  108. throw new Error(getErrorMessage([!repeatModifier && 'repeat modifier', !releaseSelfModifier && 'release modifier', `"${expectedEndBracket}"`].filter(Boolean).join(' or '), text[pos], text));
  109. }
  110. pos += endBracket.length;
  111. return {
  112. consumedLength: pos,
  113. descriptor,
  114. releasePrevious: !!releasePreviousModifier,
  115. repeat: repeatModifier ? Math.max(Number(repeatModifier.substr(1)), 1) : 1,
  116. releaseSelf: hasReleaseSelf(startBracket, descriptor, releaseSelfModifier, repeatModifier)
  117. };
  118. }
  119. function assertDescriptor(descriptor, text, pos) {
  120. if (!descriptor) {
  121. throw new Error(getErrorMessage('key descriptor', text[pos], text));
  122. }
  123. }
  124. function getEnumValue(f, key) {
  125. return f[key];
  126. }
  127. function hasReleaseSelf(startBracket, descriptor, releaseSelfModifier, repeatModifier) {
  128. if (releaseSelfModifier) {
  129. return releaseSelfModifier === '/';
  130. }
  131. if (repeatModifier) {
  132. return false;
  133. }
  134. if (startBracket === '{' && getEnumValue(legacyModifiers, descriptor.toLowerCase())) {
  135. return false;
  136. }
  137. return true;
  138. }
  139. function mapLegacyKey(descriptor) {
  140. var _getEnumValue;
  141. return (_getEnumValue = getEnumValue(legacyKeyMap, descriptor)) != null ? _getEnumValue : descriptor;
  142. }
  143. function getErrorMessage(expected, found, text) {
  144. return `Expected ${expected} but found "${found != null ? found : ''}" in "${text}"
  145. See https://github.com/testing-library/user-event/blob/main/README.md#keyboardtext-options
  146. for more information about how userEvent parses your input.`;
  147. }