A stylesheet language written in TypeScript that compiles to CSS
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import * as test from 'tape';
  2. import Lexer, { LexerError, LexerResult } from '../lexer';
  3. import Token, { TokenTypes as TT } from '../token';
  4. const scan = (source: string): LexerResult => {
  5. return new Lexer(source).scan();
  6. };
  7. const EOF = (line: number = 1) => new Token(TT.EOF, 'eof', line);
  8. test('scans punctuation', (t) => {
  9. t.plan(2);
  10. const result: LexerResult = scan('(),');
  11. t.false(result instanceof LexerError);
  12. if (!(result instanceof LexerError)) {
  13. t.deepEqual(result.tokens.map((t) => t.type), [
  14. TT.LPAREN,
  15. TT.RPAREN,
  16. TT.COMMA,
  17. TT.EOF,
  18. ]);
  19. }
  20. });
  21. test('scans property', (t) => {
  22. t.plan(2);
  23. const result: LexerResult = scan(':property');
  24. t.false(result instanceof LexerError);
  25. if (!(result instanceof LexerError)) {
  26. t.deepEqual(result.tokens, [new Token(TT.PROPERTY, 'property', 1), EOF()]);
  27. }
  28. });
  29. test('scans identifier', (t) => {
  30. t.plan(2);
  31. const result: LexerResult = scan('$identifier');
  32. t.false(result instanceof LexerError);
  33. if (!(result instanceof LexerError)) {
  34. t.deepEqual(result.tokens, [
  35. new Token(TT.IDENTIFIER, 'identifier', 1),
  36. EOF(),
  37. ]);
  38. }
  39. });
  40. test('scans function name', (t) => {
  41. t.plan(2);
  42. const result: LexerResult = scan('@function_name');
  43. t.false(result instanceof LexerError);
  44. if (!(result instanceof LexerError)) {
  45. t.deepEqual(result.tokens, [
  46. new Token(TT.FUNCTION_NAME, 'function_name', 1),
  47. EOF(),
  48. ]);
  49. }
  50. });
  51. test('scans literal', (t) => {
  52. t.plan(2);
  53. const result: LexerResult = scan('literal');
  54. t.false(result instanceof LexerError);
  55. if (!(result instanceof LexerError)) {
  56. t.deepEqual(result.tokens, [new Token(TT.LITERAL, 'literal', 1), EOF()]);
  57. }
  58. });
  59. test('scans literal followed by parens', (t) => {
  60. t.plan(2);
  61. const result: LexerResult = scan('literal(literal)literal (');
  62. t.false(result instanceof LexerError);
  63. if (!(result instanceof LexerError)) {
  64. t.deepEqual(result.tokens, [
  65. new Token(TT.LITERAL, 'literal', 1),
  66. new Token(TT.LPAREN, '(', 1),
  67. new Token(TT.LITERAL, 'literal', 1),
  68. new Token(TT.RPAREN, ')', 1),
  69. new Token(TT.LITERAL, 'literal', 1),
  70. new Token(TT.LPAREN, '(', 1),
  71. EOF(),
  72. ]);
  73. }
  74. });
  75. test('scans literal followed by property', (t) => {
  76. t.plan(2);
  77. const result: LexerResult = scan('literal :property');
  78. t.false(result instanceof LexerError);
  79. if (!(result instanceof LexerError)) {
  80. t.deepEqual(result.tokens, [
  81. new Token(TT.LITERAL, 'literal', 1),
  82. new Token(TT.PROPERTY, 'property', 1),
  83. EOF(),
  84. ]);
  85. }
  86. });
  87. test('scans simple expression', (t) => {
  88. t.plan(2);
  89. const result: LexerResult = scan('(div :color blue)');
  90. t.false(result instanceof LexerError);
  91. if (!(result instanceof LexerError)) {
  92. t.deepEqual(result.tokens, [
  93. new Token(TT.LPAREN, '(', 1),
  94. new Token(TT.LITERAL, 'div', 1),
  95. new Token(TT.PROPERTY, 'color', 1),
  96. new Token(TT.LITERAL, 'blue', 1),
  97. new Token(TT.RPAREN, ')', 1),
  98. EOF(),
  99. ]);
  100. }
  101. });
  102. test('keeps track of line numbers', (t) => {
  103. t.plan(2);
  104. const result: LexerResult = scan('line1\nline2');
  105. t.false(result instanceof LexerError);
  106. if (!(result instanceof LexerError)) {
  107. t.deepEqual(result.tokens, [
  108. new Token(TT.LITERAL, 'line1', 1),
  109. new Token(TT.LITERAL, 'line2', 2),
  110. EOF(2),
  111. ]);
  112. }
  113. });
  114. test('scans literal followed by identifier', (t) => {
  115. t.plan(2);
  116. const result: LexerResult = scan('literal $identifier');
  117. t.false(result instanceof LexerError);
  118. if (!(result instanceof LexerError)) {
  119. t.deepEqual(result.tokens, [
  120. new Token(TT.LITERAL, 'literal', 1),
  121. new Token(TT.IDENTIFIER, 'identifier', 1),
  122. EOF(),
  123. ]);
  124. }
  125. });
  126. test('allow dashes', (t) => {
  127. t.plan(2);
  128. const result: LexerResult = scan(
  129. 'literal-dash $identifier-dash @function-dash'
  130. );
  131. t.false(result instanceof LexerError);
  132. if (!(result instanceof LexerError)) {
  133. t.deepEqual(result.tokens, [
  134. new Token(TT.LITERAL, 'literal-dash', 1),
  135. new Token(TT.IDENTIFIER, 'identifier-dash', 1),
  136. new Token(TT.FUNCTION_NAME, 'function-dash', 1),
  137. EOF(),
  138. ]);
  139. }
  140. });
  141. test('disallow whitespace in function arguments', (t) => {
  142. t.plan(2);
  143. const result: LexerResult = scan('(@rgba 0 0 0 0)');
  144. t.false(result instanceof LexerError);
  145. if (!(result instanceof LexerError)) {
  146. t.deepEqual(result.tokens, [
  147. new Token(TT.LPAREN, '(', 1),
  148. new Token(TT.FUNCTION_NAME, 'rgba', 1),
  149. new Token(TT.LITERAL, '0', 1),
  150. new Token(TT.LITERAL, '0', 1),
  151. new Token(TT.LITERAL, '0', 1),
  152. new Token(TT.LITERAL, '0', 1),
  153. new Token(TT.RPAREN, ')', 1),
  154. EOF(),
  155. ]);
  156. }
  157. });
  158. test('ignores comments', (t) => {
  159. t.plan(2);
  160. const result: LexerResult = scan('; div with blue text\n(div :color blue)');
  161. t.false(result instanceof LexerError);
  162. if (!(result instanceof LexerError)) {
  163. t.deepEqual(result.tokens, [
  164. new Token(TT.LPAREN, '(', 2),
  165. new Token(TT.LITERAL, 'div', 2),
  166. new Token(TT.PROPERTY, 'color', 2),
  167. new Token(TT.LITERAL, 'blue', 2),
  168. new Token(TT.RPAREN, ')', 2),
  169. EOF(2),
  170. ]);
  171. }
  172. });