|
1 | 1 | import { describe, test, expect } from 'vitest' |
2 | | -import { Parser } from './parser' |
3 | | -// TODO: the node types should be re-exported from parser |
4 | | -import { NODE_STYLESHEET, NODE_STYLE_RULE, NODE_AT_RULE, NODE_DECLARATION } from './arena' |
| 2 | +import { Parser, NODE_STYLESHEET, NODE_STYLE_RULE, NODE_AT_RULE, NODE_DECLARATION } from './parser' |
5 | 3 |
|
6 | 4 | describe('Parser', () => { |
7 | 5 | describe('basic parsing', () => { |
@@ -201,12 +199,12 @@ describe('Parser', () => { |
201 | 199 | test('should parse @import', () => { |
202 | 200 | const source = '@import url("style.css");' |
203 | 201 | const parser = new Parser(source, { parse_atrule_preludes: false }) |
204 | | - const root = parser.parse() |
| 202 | + const root = parser.parse() |
205 | 203 |
|
206 | | - const atRule = root.first_child! |
207 | | - expect(atRule.type).toBe(NODE_AT_RULE) |
208 | | - expect(atRule.name).toBe('import') |
209 | | - expect(atRule.has_children).toBe(false) |
| 204 | + const atRule = root.first_child! |
| 205 | + expect(atRule.type).toBe(NODE_AT_RULE) |
| 206 | + expect(atRule.name).toBe('import') |
| 207 | + expect(atRule.has_children).toBe(false) |
210 | 208 | }) |
211 | 209 |
|
212 | 210 | test('should parse @namespace', () => { |
@@ -708,6 +706,138 @@ describe('Parser', () => { |
708 | 706 | }) |
709 | 707 | }) |
710 | 708 |
|
| 709 | + describe('vendor prefix detection', () => { |
| 710 | + test('should detect -webkit- vendor prefix', () => { |
| 711 | + let source = '.box { -webkit-transform: scale(1); }' |
| 712 | + let parser = new Parser(source) |
| 713 | + let root = parser.parse() |
| 714 | + |
| 715 | + let rule = root.first_child! |
| 716 | + let [_selector, decl] = rule.children |
| 717 | + expect(decl.name).toBe('-webkit-transform') |
| 718 | + expect(decl.is_vendor_prefixed).toBe(true) |
| 719 | + }) |
| 720 | + |
| 721 | + test('should detect -moz- vendor prefix', () => { |
| 722 | + let source = '.box { -moz-transform: scale(1); }' |
| 723 | + let parser = new Parser(source) |
| 724 | + let root = parser.parse() |
| 725 | + |
| 726 | + let rule = root.first_child! |
| 727 | + let [_selector, decl] = rule.children |
| 728 | + expect(decl.name).toBe('-moz-transform') |
| 729 | + expect(decl.is_vendor_prefixed).toBe(true) |
| 730 | + }) |
| 731 | + |
| 732 | + test('should detect -ms- vendor prefix', () => { |
| 733 | + let source = '.box { -ms-transform: scale(1); }' |
| 734 | + let parser = new Parser(source) |
| 735 | + let root = parser.parse() |
| 736 | + |
| 737 | + let rule = root.first_child! |
| 738 | + let [_selector, decl] = rule.children |
| 739 | + expect(decl.name).toBe('-ms-transform') |
| 740 | + expect(decl.is_vendor_prefixed).toBe(true) |
| 741 | + }) |
| 742 | + |
| 743 | + test('should detect -o- vendor prefix', () => { |
| 744 | + let source = '.box { -o-transform: scale(1); }' |
| 745 | + let parser = new Parser(source) |
| 746 | + let root = parser.parse() |
| 747 | + |
| 748 | + let rule = root.first_child! |
| 749 | + let [_selector, decl] = rule.children |
| 750 | + expect(decl.name).toBe('-o-transform') |
| 751 | + expect(decl.is_vendor_prefixed).toBe(true) |
| 752 | + }) |
| 753 | + |
| 754 | + test('should not detect vendor prefix for standard properties', () => { |
| 755 | + let source = '.box { transform: scale(1); }' |
| 756 | + let parser = new Parser(source) |
| 757 | + let root = parser.parse() |
| 758 | + |
| 759 | + let rule = root.first_child! |
| 760 | + let [_selector, decl] = rule.children |
| 761 | + expect(decl.name).toBe('transform') |
| 762 | + expect(decl.is_vendor_prefixed).toBe(false) |
| 763 | + }) |
| 764 | + |
| 765 | + test('should not detect vendor prefix for properties with hyphens', () => { |
| 766 | + let source = '.box { background-color: red; }' |
| 767 | + let parser = new Parser(source) |
| 768 | + let root = parser.parse() |
| 769 | + |
| 770 | + let rule = root.first_child! |
| 771 | + let [_selector, decl] = rule.children |
| 772 | + expect(decl.name).toBe('background-color') |
| 773 | + expect(decl.is_vendor_prefixed).toBe(false) |
| 774 | + }) |
| 775 | + |
| 776 | + test('should not detect vendor prefix for custom properties', () => { |
| 777 | + let source = ':root { --primary-color: blue; }' |
| 778 | + let parser = new Parser(source) |
| 779 | + let root = parser.parse() |
| 780 | + |
| 781 | + let rule = root.first_child! |
| 782 | + let [_selector, decl] = rule.children |
| 783 | + expect(decl.name).toBe('--primary-color') |
| 784 | + expect(decl.is_vendor_prefixed).toBe(false) |
| 785 | + }) |
| 786 | + |
| 787 | + test('should detect vendor prefix with multiple vendor-prefixed properties', () => { |
| 788 | + let source = '.box { -webkit-transform: scale(1); -moz-transform: scale(1); transform: scale(1); }' |
| 789 | + let parser = new Parser(source) |
| 790 | + let root = parser.parse() |
| 791 | + |
| 792 | + let rule = root.first_child! |
| 793 | + let [_selector, webkit, moz, standard] = rule.children |
| 794 | + |
| 795 | + expect(webkit.name).toBe('-webkit-transform') |
| 796 | + expect(webkit.is_vendor_prefixed).toBe(true) |
| 797 | + |
| 798 | + expect(moz.name).toBe('-moz-transform') |
| 799 | + expect(moz.is_vendor_prefixed).toBe(true) |
| 800 | + |
| 801 | + expect(standard.name).toBe('transform') |
| 802 | + expect(standard.is_vendor_prefixed).toBe(false) |
| 803 | + }) |
| 804 | + |
| 805 | + test('should detect vendor prefix for complex property names', () => { |
| 806 | + let source = '.box { -webkit-border-top-left-radius: 5px; }' |
| 807 | + let parser = new Parser(source) |
| 808 | + let root = parser.parse() |
| 809 | + |
| 810 | + let rule = root.first_child! |
| 811 | + let [_selector, decl] = rule.children |
| 812 | + expect(decl.name).toBe('-webkit-border-top-left-radius') |
| 813 | + expect(decl.is_vendor_prefixed).toBe(true) |
| 814 | + }) |
| 815 | + |
| 816 | + test('should not detect vendor prefix for similar but non-vendor properties', () => { |
| 817 | + // Edge case: property that starts with hyphen but isn't a vendor prefix |
| 818 | + let source = '.box { border-radius: 5px; }' |
| 819 | + let parser = new Parser(source) |
| 820 | + let root = parser.parse() |
| 821 | + |
| 822 | + let rule = root.first_child! |
| 823 | + let [_selector, decl] = rule.children |
| 824 | + expect(decl.name).toBe('border-radius') |
| 825 | + expect(decl.is_vendor_prefixed).toBe(false) |
| 826 | + }) |
| 827 | + |
| 828 | + test('should return false for nodes without names', () => { |
| 829 | + // Nodes like selectors or at-rules without property names |
| 830 | + let source = 'body { }' |
| 831 | + let parser = new Parser(source) |
| 832 | + let root = parser.parse() |
| 833 | + |
| 834 | + let rule = root.first_child! |
| 835 | + let selector = rule.first_child! |
| 836 | + // Selectors have text but checking is_vendor_prefixed should be safe |
| 837 | + expect(selector.is_vendor_prefixed).toBe(false) |
| 838 | + }) |
| 839 | + }) |
| 840 | + |
711 | 841 | describe('complex real-world scenarios', () => { |
712 | 842 | test('should parse complex nested structure', () => { |
713 | 843 | let source = ` |
|
0 commit comments