|
1 | 1 | import { describe, it, expect } from 'vitest' |
2 | 2 | import { parse } from './parse' |
3 | | -import { IDENTIFIER, NUMBER, DIMENSION, STRING, HASH, FUNCTION, OPERATOR, PARENTHESIS, URL, VALUE } from './arena' |
| 3 | +import { IDENTIFIER, NUMBER, DIMENSION, STRING, HASH, FUNCTION, OPERATOR, PARENTHESIS, URL, UNICODE_RANGE, VALUE } from './arena' |
4 | 4 |
|
5 | 5 | describe('Value Node Types', () => { |
6 | 6 | // Helper to get first value node from a declaration |
@@ -217,6 +217,30 @@ describe('Value Node Types', () => { |
217 | 217 | expect(value?.column).toBe(15) |
218 | 218 | }) |
219 | 219 | }) |
| 220 | + |
| 221 | + describe('UNICODE_RANGE', () => { |
| 222 | + it('should have correct offset and length', () => { |
| 223 | + const root = parse('@font-face { unicode-range: u+0025-00ff; }') |
| 224 | + const declaration = root.first_child?.block?.first_child |
| 225 | + const value = declaration?.first_child?.children[0] |
| 226 | + expect(value?.start).toBe(28) |
| 227 | + expect(value?.length).toBe(11) |
| 228 | + expect(value?.end).toBe(39) |
| 229 | + expect(value?.line).toBe(1) |
| 230 | + expect(value?.column).toBe(29) |
| 231 | + }) |
| 232 | + |
| 233 | + it('should have correct line and column on line 2', () => { |
| 234 | + const root = parse('@font-face {\n unicode-range: u+4??;\n}') |
| 235 | + const declaration = root.first_child?.block?.first_child |
| 236 | + const value = declaration?.first_child?.children[0] |
| 237 | + expect(value?.start).toBe(30) |
| 238 | + expect(value?.length).toBe(5) |
| 239 | + expect(value?.end).toBe(35) |
| 240 | + expect(value?.line).toBe(2) |
| 241 | + expect(value?.column).toBe(18) |
| 242 | + }) |
| 243 | + }) |
220 | 244 | }) |
221 | 245 |
|
222 | 246 | describe('Types', () => { |
@@ -267,6 +291,14 @@ describe('Value Node Types', () => { |
267 | 291 | const value = getValue('div { background: url("image.png"); }') |
268 | 292 | expect(value?.type).toBe(URL) |
269 | 293 | }) |
| 294 | + |
| 295 | + it('UNICODE_RANGE type constant', () => { |
| 296 | + const root = parse('@font-face { unicode-range: u+0460-052f, u+1c80-1c8a, u+20b4, u+2de0-2dff, u+a640-a69f, u+fe2e-fe2f; }') |
| 297 | + const atrule = root.first_child |
| 298 | + const declaration = atrule?.block?.first_child |
| 299 | + const unicode_range = declaration?.first_child?.children[0] |
| 300 | + expect(unicode_range?.type).toBe(UNICODE_RANGE) |
| 301 | + }) |
270 | 302 | }) |
271 | 303 |
|
272 | 304 | describe('Type Names', () => { |
@@ -317,6 +349,12 @@ describe('Value Node Types', () => { |
317 | 349 | const value = getValue('div { background: url("image.png"); }') |
318 | 350 | expect(value?.type_name).toBe('Url') |
319 | 351 | }) |
| 352 | + |
| 353 | + it('UNICODE_RANGE type_name', () => { |
| 354 | + const root = parse('@font-face { unicode-range: u+0025-00ff; }') |
| 355 | + const unicode_range = root.first_child?.block?.first_child?.first_child?.children[0] |
| 356 | + expect(unicode_range?.type_name).toBe('UnicodeRange') |
| 357 | + }) |
320 | 358 | }) |
321 | 359 |
|
322 | 360 | describe('Value Properties', () => { |
@@ -759,6 +797,90 @@ describe('Value Node Types', () => { |
759 | 797 | }) |
760 | 798 | }) |
761 | 799 |
|
| 800 | + describe('UNICODE_RANGE', () => { |
| 801 | + it('should parse simple unicode range', () => { |
| 802 | + const root = parse('@font-face { unicode-range: u+0025-00ff; }') |
| 803 | + const decl = root.first_child?.block?.first_child |
| 804 | + |
| 805 | + expect(decl?.first_child!.children).toHaveLength(1) |
| 806 | + expect(decl?.first_child!.children[0].type).toBe(UNICODE_RANGE) |
| 807 | + expect(decl?.first_child!.children[0].text).toBe('u+0025-00ff') |
| 808 | + }) |
| 809 | + |
| 810 | + it('should parse single codepoint', () => { |
| 811 | + const root = parse('@font-face { unicode-range: u+26; }') |
| 812 | + const decl = root.first_child?.block?.first_child |
| 813 | + |
| 814 | + expect(decl?.first_child!.children).toHaveLength(1) |
| 815 | + expect(decl?.first_child!.children[0].type).toBe(UNICODE_RANGE) |
| 816 | + expect(decl?.first_child!.children[0].text).toBe('u+26') |
| 817 | + }) |
| 818 | + |
| 819 | + it('should parse wildcard pattern with question marks', () => { |
| 820 | + const root = parse('@font-face { unicode-range: u+4??; }') |
| 821 | + const decl = root.first_child?.block?.first_child |
| 822 | + |
| 823 | + expect(decl?.first_child!.children).toHaveLength(1) |
| 824 | + expect(decl?.first_child!.children[0].type).toBe(UNICODE_RANGE) |
| 825 | + expect(decl?.first_child!.children[0].text).toBe('u+4??') |
| 826 | + }) |
| 827 | + |
| 828 | + it('should parse uppercase U+', () => { |
| 829 | + const root = parse('@font-face { unicode-range: U+0025-00FF; }') |
| 830 | + const decl = root.first_child?.block?.first_child |
| 831 | + |
| 832 | + expect(decl?.first_child!.children).toHaveLength(1) |
| 833 | + expect(decl?.first_child!.children[0].type).toBe(UNICODE_RANGE) |
| 834 | + expect(decl?.first_child!.children[0].text).toBe('U+0025-00FF') |
| 835 | + }) |
| 836 | + |
| 837 | + it('should parse multiple unicode ranges', () => { |
| 838 | + const root = parse('@font-face { unicode-range: u+0460-052f, u+1c80-1c8a, u+20b4; }') |
| 839 | + const decl = root.first_child?.block?.first_child |
| 840 | + |
| 841 | + expect(decl?.first_child!.children).toHaveLength(5) // 3 ranges + 2 commas |
| 842 | + expect(decl?.first_child!.children[0].type).toBe(UNICODE_RANGE) |
| 843 | + expect(decl?.first_child!.children[0].text).toBe('u+0460-052f') |
| 844 | + expect(decl?.first_child!.children[1].type).toBe(OPERATOR) |
| 845 | + expect(decl?.first_child!.children[1].text).toBe(',') |
| 846 | + expect(decl?.first_child!.children[2].type).toBe(UNICODE_RANGE) |
| 847 | + expect(decl?.first_child!.children[2].text).toBe('u+1c80-1c8a') |
| 848 | + expect(decl?.first_child!.children[3].type).toBe(OPERATOR) |
| 849 | + expect(decl?.first_child!.children[4].type).toBe(UNICODE_RANGE) |
| 850 | + expect(decl?.first_child!.children[4].text).toBe('u+20b4') |
| 851 | + }) |
| 852 | + |
| 853 | + it('should parse short hex values', () => { |
| 854 | + const root = parse('@font-face { unicode-range: u+0; }') |
| 855 | + const decl = root.first_child?.block?.first_child |
| 856 | + |
| 857 | + expect(decl?.first_child!.children[0].type).toBe(UNICODE_RANGE) |
| 858 | + expect(decl?.first_child!.children[0].text).toBe('u+0') |
| 859 | + }) |
| 860 | + |
| 861 | + it('should parse maximum valid unicode', () => { |
| 862 | + const root = parse('@font-face { unicode-range: u+10ffff; }') |
| 863 | + const decl = root.first_child?.block?.first_child |
| 864 | + |
| 865 | + expect(decl?.first_child!.children[0].type).toBe(UNICODE_RANGE) |
| 866 | + expect(decl?.first_child!.children[0].text).toBe('u+10ffff') |
| 867 | + }) |
| 868 | + |
| 869 | + it('should parse wildcard variations', () => { |
| 870 | + const root = parse('@font-face { unicode-range: u+?, u+??, u+???, u+????, u+?????, u+??????; }') |
| 871 | + const decl = root.first_child?.block?.first_child |
| 872 | + |
| 873 | + expect(decl?.first_child!.children[0].type).toBe(UNICODE_RANGE) |
| 874 | + expect(decl?.first_child!.children[0].text).toBe('u+?') |
| 875 | + expect(decl?.first_child!.children[2].type).toBe(UNICODE_RANGE) |
| 876 | + expect(decl?.first_child!.children[2].text).toBe('u+??') |
| 877 | + expect(decl?.first_child!.children[4].type).toBe(UNICODE_RANGE) |
| 878 | + expect(decl?.first_child!.children[4].text).toBe('u+???') |
| 879 | + expect(decl?.first_child!.children[10].type).toBe(UNICODE_RANGE) |
| 880 | + expect(decl?.first_child!.children[10].text).toBe('u+??????') |
| 881 | + }) |
| 882 | + }) |
| 883 | + |
762 | 884 | describe('Mixed values', () => { |
763 | 885 | it('should parse mixed value types', () => { |
764 | 886 | const root = parse('body { border: 1px solid red; }') |
|
0 commit comments