@thumbmarkjs/thumbmarkjs 1.7.2 → 1.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,62 +12,48 @@ import { getBrowser } from "../components/system/browser";
12
12
  * @param options - Filtering options
13
13
  * @returns Filtered object
14
14
  */
15
- export function filterThumbmarkData(
16
- obj: componentInterface,
17
- options?: optionsInterface,
18
- ): componentInterface {
19
- // Get current browser name and version
15
+ /**
16
+ * Builds the full exclusion list from user options and stabilization rules,
17
+ * taking browser detection into account.
18
+ */
19
+ export function getExcludeList(options?: optionsInterface, obj?: componentInterface): string[] {
20
20
  let browser = getBrowser();
21
-
22
- // Fallback to browser info from components if getBrowser() returns unknown (server-side)
23
- if (browser.name === 'unknown' && obj.system && typeof obj.system === 'object' && !Array.isArray(obj.system)) {
24
- const systemComponent = obj.system as componentInterface;
25
- const browserInfo = systemComponent.browser;
26
- if (browserInfo && typeof browserInfo === 'object' && !Array.isArray(browserInfo)) {
27
- const browserComponent = browserInfo as componentInterface;
28
- browser = {
29
- name: (browserComponent.name as string) || 'unknown',
30
- version: (browserComponent.version as string) || 'unknown'
31
- };
32
- }
21
+
22
+ // Fallback to component data when getBrowser() returns unknown (server-side)
23
+ if (browser.name === 'unknown' && obj) {
24
+ const b = (obj.system as componentInterface)?.browser as componentInterface | undefined;
25
+ if (b?.name) browser = { name: String(b.name), version: String(b.version || 'unknown') };
33
26
  }
34
-
35
- const name = browser.name.toLowerCase();
36
- const ver = browser.version.split('.')[0] || '0';
37
- const majorVer = parseInt(ver, 10);
38
27
 
39
- // Initialize excludeList with user-defined exclusions from options
28
+ const name = browser.name.toLowerCase();
29
+ const majorVer = parseInt(browser.version.split('.')[0] || '0', 10);
40
30
  const excludeList = [...(options?.exclude || [])];
41
- const stabilizationOptions = options?.stabilize || [];
42
- const includeList = options?.include || [];
31
+ const stabilizationOptions = [...new Set([...(options?.stabilize || []), 'always'])];
43
32
 
44
- // Expand the excludeList based on stabilization rules
45
33
  for (const option of stabilizationOptions) {
46
34
  const rules = stabilizationExclusionRules[option as keyof typeof stabilizationExclusionRules];
47
35
  if (!rules) continue;
48
36
 
49
37
  for (const rule of rules) {
50
- // A rule applies to all browsers if the 'browsers' key is not present.
51
- const appliesToAllBrowsers = !('browsers' in rule);
52
-
53
- // The 'rule.browsers?' optional chaining here safely handles the case where 'browsers' is missing.
54
- const browserMatch = !appliesToAllBrowsers && rule.browsers?.some(browserRule => {
55
- const match = browserRule.match(/(.+?)(>=)(\d+)/);
56
-
57
- if (match) {
58
- const [, ruleName, , ruleVersionStr] = match;
59
- const ruleVersion = parseInt(ruleVersionStr, 10);
60
- return name === ruleName && majorVer >= ruleVersion;
61
- }
62
- return name === browserRule;
63
- });
64
-
65
- if (appliesToAllBrowsers || browserMatch) {
38
+ if (!('browsers' in rule) || rule.browsers?.some(br => {
39
+ const m = br.match(/(.+?)(>=)(\d+)/);
40
+ return m ? name === m[1] && majorVer >= +m[3] : name === br;
41
+ })) {
66
42
  excludeList.push(...rule.exclude);
67
43
  }
68
44
  }
69
45
  }
70
46
 
47
+ return excludeList;
48
+ }
49
+
50
+ export function filterThumbmarkData(
51
+ obj: componentInterface,
52
+ options?: optionsInterface,
53
+ ): componentInterface {
54
+ const excludeList = getExcludeList(options, obj);
55
+ const includeList = options?.include || [];
56
+
71
57
  /**
72
58
  * Inner recursive function to perform the actual filtering.
73
59
  * Uses the fully prepared excludeList and includeList from the parent scope.
@@ -18,7 +18,7 @@ import {
18
18
  import { hash } from "../utils/hash";
19
19
  import { raceAllPerformance } from "../utils/raceAll";
20
20
  import { getVersion } from "../utils/version";
21
- import { filterThumbmarkData } from './filterComponents'
21
+ import { filterThumbmarkData, getExcludeList } from './filterComponents'
22
22
  import { logThumbmarkData } from '../utils/log';
23
23
  import { getApiPromise, infoInterface } from "./api";
24
24
  import { stableStringify } from "../utils/stableStringify";
@@ -180,8 +180,10 @@ export async function resolveClientComponents(
180
180
  options?: optionsInterface
181
181
  ): Promise<{ elapsed: Record<string, number>, resolvedComponents: componentInterface, errors: ThumbmarkError[] }> {
182
182
  const opts = { ...defaultOptions, ...options };
183
+ const topLevelExcludes = getExcludeList(opts).filter(e => !e.includes('.'));
183
184
  const filtered = Object.entries(comps)
184
185
  .filter(([key]) => !opts?.exclude?.includes(key))
186
+ .filter(([key]) => !topLevelExcludes.includes(key))
185
187
  .filter(([key]) =>
186
188
  opts?.include?.some(e => e.includes('.'))
187
189
  ? opts?.include?.some(e => e.startsWith(key))
package/src/options.ts CHANGED
@@ -97,4 +97,7 @@ export const stabilizationExclusionRules = {
97
97
  'vpn': [
98
98
  { exclude: ['ip'] },
99
99
  ],
100
+ 'always': [
101
+ { exclude: ['speech'], browsers: ['brave', 'firefox'] },
102
+ ],
100
103
  }