accept-header.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.acceptLanguage = acceptLanguage;
  6. function parse(raw, preferences, options) {
  7. const lowers = new Map();
  8. const header = raw.replace(/[ \t]/g, "");
  9. if (preferences) {
  10. let pos = 0;
  11. for (const preference of preferences){
  12. const lower = preference.toLowerCase();
  13. lowers.set(lower, {
  14. orig: preference,
  15. pos: pos++
  16. });
  17. if (options.prefixMatch) {
  18. const parts = lower.split("-");
  19. while(parts.pop(), parts.length > 0){
  20. const joined = parts.join("-");
  21. if (!lowers.has(joined)) {
  22. lowers.set(joined, {
  23. orig: preference,
  24. pos: pos++
  25. });
  26. }
  27. }
  28. }
  29. }
  30. }
  31. const parts = header.split(",");
  32. const selections = [];
  33. const map = new Set();
  34. for(let i = 0; i < parts.length; ++i){
  35. const part = parts[i];
  36. if (!part) {
  37. continue;
  38. }
  39. const params = part.split(";");
  40. if (params.length > 2) {
  41. throw new Error(`Invalid ${options.type} header`);
  42. }
  43. let token = params[0].toLowerCase();
  44. if (!token) {
  45. throw new Error(`Invalid ${options.type} header`);
  46. }
  47. const selection = {
  48. token,
  49. pos: i,
  50. q: 1
  51. };
  52. if (preferences && lowers.has(token)) {
  53. selection.pref = lowers.get(token).pos;
  54. }
  55. map.add(selection.token);
  56. if (params.length === 2) {
  57. const q = params[1];
  58. const [key, value] = q.split("=");
  59. if (!value || key !== "q" && key !== "Q") {
  60. throw new Error(`Invalid ${options.type} header`);
  61. }
  62. const score = parseFloat(value);
  63. if (score === 0) {
  64. continue;
  65. }
  66. if (Number.isFinite(score) && score <= 1 && score >= 0.001) {
  67. selection.q = score;
  68. }
  69. }
  70. selections.push(selection);
  71. }
  72. selections.sort((a, b)=>{
  73. if (b.q !== a.q) {
  74. return b.q - a.q;
  75. }
  76. if (b.pref !== a.pref) {
  77. if (a.pref === undefined) {
  78. return 1;
  79. }
  80. if (b.pref === undefined) {
  81. return -1;
  82. }
  83. return a.pref - b.pref;
  84. }
  85. return a.pos - b.pos;
  86. });
  87. const values = selections.map((selection)=>selection.token);
  88. if (!preferences || !preferences.length) {
  89. return values;
  90. }
  91. const preferred = [];
  92. for (const selection1 of values){
  93. if (selection1 === "*") {
  94. for (const [preference, value] of lowers){
  95. if (!map.has(preference)) {
  96. preferred.push(value.orig);
  97. }
  98. }
  99. } else {
  100. const lower = selection1.toLowerCase();
  101. if (lowers.has(lower)) {
  102. preferred.push(lowers.get(lower).orig);
  103. }
  104. }
  105. }
  106. return preferred;
  107. }
  108. function acceptLanguage(header = "", preferences) {
  109. return parse(header, preferences, {
  110. type: "accept-language",
  111. prefixMatch: true
  112. })[0] || "";
  113. }
  114. //# sourceMappingURL=accept-header.js.map