1 | var hasOwnProperty = Object.prototype.hasOwnProperty;
|
---|
2 | var keywords = Object.create(null);
|
---|
3 | var properties = Object.create(null);
|
---|
4 | var HYPHENMINUS = 45; // '-'.charCodeAt()
|
---|
5 |
|
---|
6 | function isCustomProperty(str, offset) {
|
---|
7 | offset = offset || 0;
|
---|
8 |
|
---|
9 | return str.length - offset >= 2 &&
|
---|
10 | str.charCodeAt(offset) === HYPHENMINUS &&
|
---|
11 | str.charCodeAt(offset + 1) === HYPHENMINUS;
|
---|
12 | }
|
---|
13 |
|
---|
14 | function getVendorPrefix(str, offset) {
|
---|
15 | offset = offset || 0;
|
---|
16 |
|
---|
17 | // verdor prefix should be at least 3 chars length
|
---|
18 | if (str.length - offset >= 3) {
|
---|
19 | // vendor prefix starts with hyper minus following non-hyper minus
|
---|
20 | if (str.charCodeAt(offset) === HYPHENMINUS &&
|
---|
21 | str.charCodeAt(offset + 1) !== HYPHENMINUS) {
|
---|
22 | // vendor prefix should contain a hyper minus at the ending
|
---|
23 | var secondDashIndex = str.indexOf('-', offset + 2);
|
---|
24 |
|
---|
25 | if (secondDashIndex !== -1) {
|
---|
26 | return str.substring(offset, secondDashIndex + 1);
|
---|
27 | }
|
---|
28 | }
|
---|
29 | }
|
---|
30 |
|
---|
31 | return '';
|
---|
32 | }
|
---|
33 |
|
---|
34 | function getKeywordDescriptor(keyword) {
|
---|
35 | if (hasOwnProperty.call(keywords, keyword)) {
|
---|
36 | return keywords[keyword];
|
---|
37 | }
|
---|
38 |
|
---|
39 | var name = keyword.toLowerCase();
|
---|
40 |
|
---|
41 | if (hasOwnProperty.call(keywords, name)) {
|
---|
42 | return keywords[keyword] = keywords[name];
|
---|
43 | }
|
---|
44 |
|
---|
45 | var custom = isCustomProperty(name, 0);
|
---|
46 | var vendor = !custom ? getVendorPrefix(name, 0) : '';
|
---|
47 |
|
---|
48 | return keywords[keyword] = Object.freeze({
|
---|
49 | basename: name.substr(vendor.length),
|
---|
50 | name: name,
|
---|
51 | vendor: vendor,
|
---|
52 | prefix: vendor,
|
---|
53 | custom: custom
|
---|
54 | });
|
---|
55 | }
|
---|
56 |
|
---|
57 | function getPropertyDescriptor(property) {
|
---|
58 | if (hasOwnProperty.call(properties, property)) {
|
---|
59 | return properties[property];
|
---|
60 | }
|
---|
61 |
|
---|
62 | var name = property;
|
---|
63 | var hack = property[0];
|
---|
64 |
|
---|
65 | if (hack === '/') {
|
---|
66 | hack = property[1] === '/' ? '//' : '/';
|
---|
67 | } else if (hack !== '_' &&
|
---|
68 | hack !== '*' &&
|
---|
69 | hack !== '$' &&
|
---|
70 | hack !== '#' &&
|
---|
71 | hack !== '+' &&
|
---|
72 | hack !== '&') {
|
---|
73 | hack = '';
|
---|
74 | }
|
---|
75 |
|
---|
76 | var custom = isCustomProperty(name, hack.length);
|
---|
77 |
|
---|
78 | // re-use result when possible (the same as for lower case)
|
---|
79 | if (!custom) {
|
---|
80 | name = name.toLowerCase();
|
---|
81 | if (hasOwnProperty.call(properties, name)) {
|
---|
82 | return properties[property] = properties[name];
|
---|
83 | }
|
---|
84 | }
|
---|
85 |
|
---|
86 | var vendor = !custom ? getVendorPrefix(name, hack.length) : '';
|
---|
87 | var prefix = name.substr(0, hack.length + vendor.length);
|
---|
88 |
|
---|
89 | return properties[property] = Object.freeze({
|
---|
90 | basename: name.substr(prefix.length),
|
---|
91 | name: name.substr(hack.length),
|
---|
92 | hack: hack,
|
---|
93 | vendor: vendor,
|
---|
94 | prefix: prefix,
|
---|
95 | custom: custom
|
---|
96 | });
|
---|
97 | }
|
---|
98 |
|
---|
99 | module.exports = {
|
---|
100 | keyword: getKeywordDescriptor,
|
---|
101 | property: getPropertyDescriptor,
|
---|
102 | isCustomProperty: isCustomProperty,
|
---|
103 | vendorPrefix: getVendorPrefix
|
---|
104 | };
|
---|