names.js 2.9 KB

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