qunitx 1.2.10 → 1.2.16

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.
@@ -1,22 +1,31 @@
1
1
  const hasOwn = Object.prototype.hasOwnProperty;
2
+ const objToString = Object.prototype.toString;
2
3
 
3
4
  export function objectType(obj: unknown): string {
4
- if (typeof obj === 'undefined') {
5
- return 'undefined';
5
+ if (obj === null) return 'null';
6
+ const t = typeof obj;
7
+ // Fast path: primitives + functions return their `typeof` directly. Skips
8
+ // the Object.prototype.toString.call() detour that allocates a "[object Foo]"
9
+ // string for every primitive check.
10
+ switch (t) {
11
+ case 'undefined':
12
+ case 'string':
13
+ case 'boolean':
14
+ case 'function':
15
+ case 'symbol':
16
+ case 'bigint':
17
+ return t;
18
+ case 'number':
19
+ // x !== x is true only for NaN.
20
+ return obj !== obj ? 'nan' : 'number';
6
21
  }
7
-
8
- // Consider: typeof null === object
9
- if (obj === null) {
10
- return 'null';
11
- }
12
- // slice(8, -1) extracts the type name from "[object Foo]" without a regex
13
- const type = Object.prototype.toString.call(obj).slice(8, -1);
22
+ // typeof === 'object': fall through to qunit.js's exact slow path so
23
+ // boxed primitives, cross-realm objects, and Symbol.toStringTag overrides
24
+ // produce the same classification as the upstream library.
25
+ const type = objToString.call(obj).slice(8, -1);
14
26
  switch (type) {
15
27
  case 'Number':
16
- if (isNaN(obj as number)) {
17
- return 'nan';
18
- }
19
- return 'number';
28
+ return isNaN(obj as number) ? 'nan' : 'number';
20
29
  case 'String':
21
30
  case 'Boolean':
22
31
  case 'Array':
@@ -28,17 +37,23 @@ export function objectType(obj: unknown): string {
28
37
  case 'Symbol':
29
38
  return type.toLowerCase();
30
39
  default:
31
- return typeof obj;
40
+ return 'object';
32
41
  }
33
42
  }
34
43
 
35
44
  export function objectValues(obj: unknown, allowArray = true): unknown {
36
- const vals: Record<string, unknown> | unknown[] = allowArray && objectType(obj) === 'array' ? [] : {};
45
+ const vals: Record<string, unknown> | unknown[] = allowArray && Array.isArray(obj) ? [] : {};
37
46
 
38
47
  for (const key in obj as object) {
39
48
  if (hasOwn.call(obj, key)) {
40
49
  const val = (obj as Record<string, unknown>)[key];
41
- (vals as Record<string, unknown>)[key] = val === Object(val) ? objectValues(val, allowArray) : val;
50
+ // `val === Object(val)` returns true for objects+functions and false for
51
+ // primitives/null — but it boxes every primitive into a wrapper object
52
+ // just to throw it away. The typeof check is the same boolean without
53
+ // the per-call allocation.
54
+ const t = typeof val;
55
+ const isObjectish = val !== null && (t === 'object' || t === 'function');
56
+ (vals as Record<string, unknown>)[key] = isObjectish ? objectValues(val, allowArray) : val;
42
57
  }
43
58
  }
44
59
 
@@ -54,9 +69,11 @@ export function objectValuesSubset(obj: unknown, model: unknown): unknown {
54
69
  // results from assert.propContains().
55
70
  // E.g. an actual null or false wrongly equaling an empty object,
56
71
  // or an actual string being reported as object not matching a partial object.
57
- if (obj !== Object(obj)) {
58
- return obj;
59
- }
72
+ // `obj !== Object(obj)` boxes primitives into wrapper objects every call —
73
+ // typeof matches the same set without allocating.
74
+ if (obj === null) return obj;
75
+ const objT = typeof obj;
76
+ if (objT !== 'object' && objT !== 'function') return obj;
60
77
 
61
78
  // Unlike objectValues(), subset arrays to a plain objects as well.
62
79
  // This enables subsetting [20, 30] with {1: 30}.
@@ -7,7 +7,8 @@ export default class ModuleContext {
7
7
  static currentModuleChain: ModuleContext[] = [];
8
8
 
9
9
  static get lastModule() {
10
- return this.currentModuleChain.at(-1);
10
+ const chain = this.currentModuleChain;
11
+ return chain[chain.length - 1];
11
12
  }
12
13
 
13
14
  name!: string;
@@ -23,11 +24,12 @@ export default class ModuleContext {
23
24
  tests: TestContext[] = [];
24
25
 
25
26
  constructor(name: string) {
26
- const parentModule = ModuleContext.currentModuleChain.at(-1);
27
+ const chain = ModuleContext.currentModuleChain;
28
+ const parentModule = chain[chain.length - 1];
27
29
 
28
- ModuleContext.currentModuleChain.push(this);
30
+ chain.push(this);
29
31
 
30
- this.moduleChain = [...ModuleContext.currentModuleChain];
32
+ this.moduleChain = chain.slice();
31
33
  this.name = parentModule ? `${parentModule.name} > ${name}` : name;
32
34
  this.assert = new ModuleContext.Assert(this);
33
35