• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

i18next / i18next / 19837025733

01 Dec 2025 08:47PM UTC coverage: 95.348% (+11.4%) from 83.922%
19837025733

push

github

adrai
TS: remove wrong signature #2372

1072 of 1172 branches covered (91.47%)

2480 of 2601 relevant lines covered (95.35%)

1091.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.33
/src/utils.js
1
export const isString = (obj) => typeof obj === 'string';
2✔
2

3
// http://lea.verou.me/2016/12/resolve-promises-externally-with-this-one-weird-trick/
2✔
4
export const defer = () => {
2✔
5
  let res;
473✔
6
  let rej;
473✔
7

8
  const promise = new Promise((resolve, reject) => {
473✔
9
    res = resolve;
473✔
10
    rej = reject;
473✔
11
  });
473✔
12

13
  promise.resolve = res;
473✔
14
  promise.reject = rej;
473✔
15

16
  return promise;
473✔
17
};
473✔
18

19
export const makeString = (object) => {
2✔
20
  if (object == null) return '';
78✔
21
  /* eslint prefer-template: 0 */
72✔
22
  return '' + object;
72✔
23
};
72✔
24

25
export const copy = (a, s, t) => {
2✔
26
  a.forEach((m) => {
253✔
27
    if (s[m]) t[m] = s[m];
1,771✔
28
  });
253✔
29
};
253✔
30

31
// We extract out the RegExp definition to improve performance with React Native Android, which has poor RegExp
2✔
32
// initialization performance
2✔
33
const lastOfPathSeparatorRegExp = /###/g;
2✔
34

35
const cleanKey = (key) =>
2✔
36
  key && key.indexOf('###') > -1 ? key.replace(lastOfPathSeparatorRegExp, '.') : key;
2!
37

38
const canNotTraverseDeeper = (object) => !object || isString(object);
2✔
39

40
const getLastOfPath = (object, path, Empty) => {
2✔
41
  const stack = !isString(path) ? path : path.split('.');
43,336✔
42
  let stackIndex = 0;
43,336✔
43
  // iterate through the stack, but leave the last item
43,336✔
44
  while (stackIndex < stack.length - 1) {
43,336✔
45
    if (canNotTraverseDeeper(object)) return {};
34,591✔
46

47
    const key = cleanKey(stack[stackIndex]);
34,588✔
48
    if (!object[key] && Empty) object[key] = new Empty();
34,591✔
49
    // prevent prototype pollution
34,588✔
50
    if (Object.prototype.hasOwnProperty.call(object, key)) {
34,590✔
51
      object = object[key];
23,780✔
52
    } else {
34,591✔
53
      object = {};
10,808✔
54
    }
10,808✔
55
    ++stackIndex;
34,588✔
56
  }
34,588✔
57

58
  if (canNotTraverseDeeper(object)) return {};
43,336✔
59
  return {
43,305✔
60
    obj: object,
43,305✔
61
    k: cleanKey(stack[stackIndex]),
43,305✔
62
  };
43,305✔
63
};
43,305✔
64

65
export const setPath = (object, path, newValue) => {
2✔
66
  const { obj, k } = getLastOfPath(object, path, Object);
10,336✔
67
  if (obj !== undefined || path.length === 1) {
10,336✔
68
    obj[k] = newValue;
10,333✔
69
    return;
10,333✔
70
  }
10,333✔
71

72
  let e = path[path.length - 1];
3✔
73
  let p = path.slice(0, path.length - 1);
3✔
74
  let last = getLastOfPath(object, p, Object);
3✔
75
  while (last.obj === undefined && p.length) {
10,336✔
76
    e = `${p[p.length - 1]}.${e}`;
1✔
77
    p = p.slice(0, p.length - 1);
1✔
78
    last = getLastOfPath(object, p, Object);
1✔
79
    if (last?.obj && typeof last.obj[`${last.k}.${e}`] !== 'undefined') {
1!
80
      last.obj = undefined;
×
81
    }
×
82
  }
1✔
83
  last.obj[`${last.k}.${e}`] = newValue;
3✔
84
};
3✔
85

86
export const pushPath = (object, path, newValue, concat) => {
2✔
87
  const { obj, k } = getLastOfPath(object, path, Object);
10,271✔
88

89
  obj[k] = obj[k] || [];
10,271✔
90
  if (concat) obj[k] = obj[k].concat(newValue);
10,271!
91
  if (!concat) obj[k].push(newValue);
10,271✔
92
};
10,271✔
93

94
export const getPath = (object, path) => {
2✔
95
  const { obj, k } = getLastOfPath(object, path);
22,725✔
96

97
  if (!obj) return undefined;
22,725✔
98
  if (!Object.prototype.hasOwnProperty.call(obj, k)) return undefined;
22,709✔
99
  return obj[k];
1,350✔
100
};
1,350✔
101

102
export const getPathWithDefaults = (data, defaultData, key) => {
2✔
103
  const value = getPath(data, key);
328✔
104
  if (value !== undefined) {
328✔
105
    return value;
314✔
106
  }
314✔
107
  // Fallback to default values
14✔
108
  return getPath(defaultData, key);
14✔
109
};
14✔
110

111
export const deepExtend = (target, source, overwrite) => {
2✔
112
  /* eslint no-restricted-syntax: 0 */
39✔
113
  for (const prop in source) {
39✔
114
    if (prop !== '__proto__' && prop !== 'constructor') {
41✔
115
      if (prop in target) {
39✔
116
        // If we reached a leaf string in target or source then replace with source or skip depending on the 'overwrite' switch
24✔
117
        if (
24✔
118
          isString(target[prop]) ||
24✔
119
          target[prop] instanceof String ||
24✔
120
          isString(source[prop]) ||
24✔
121
          source[prop] instanceof String
16✔
122
        ) {
24✔
123
          if (overwrite) target[prop] = source[prop];
8✔
124
        } else {
22✔
125
          deepExtend(target[prop], source[prop], overwrite);
16✔
126
        }
16✔
127
      } else {
39✔
128
        target[prop] = source[prop];
15✔
129
      }
15✔
130
    }
39✔
131
  }
41✔
132
  return target;
39✔
133
};
39✔
134

135
export const regexEscape = (str) =>
2✔
136
  /* eslint no-useless-escape: 0 */
1,154✔
137
  str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
2✔
138

139
/* eslint-disable */
2✔
140
var _entityMap = {
2✔
141
  '&': '&amp;',
2✔
142
  '<': '&lt;',
2✔
143
  '>': '&gt;',
2✔
144
  '"': '&quot;',
2✔
145
  "'": '&#39;',
2✔
146
  '/': '&#x2F;',
2✔
147
};
2✔
148
/* eslint-enable */
2✔
149

150
export const escape = (data) => {
2✔
151
  if (isString(data)) {
178✔
152
    return data.replace(/[&<>"'\/]/g, (s) => _entityMap[s]);
178✔
153
  }
178!
154

155
  return data;
×
156
};
×
157

158
/**
2✔
159
 * This is a reusable regular expression cache class. Given a certain maximum number of regular expressions we're
2✔
160
 * allowed to store in the cache, it provides a way to avoid recreating regular expression objects over and over.
2✔
161
 * When it needs to evict something, it evicts the oldest one.
2✔
162
 */
2✔
163
class RegExpCache {
2✔
164
  constructor(capacity) {
2✔
165
    this.capacity = capacity;
49✔
166
    this.regExpMap = new Map();
49✔
167
    // Since our capacity tends to be fairly small, `.shift()` will be fairly quick despite being O(n). We just use a
49✔
168
    // normal array to keep it simple.
49✔
169
    this.regExpQueue = [];
49✔
170
  }
49✔
171

172
  getRegExp(pattern) {
2✔
173
    const regExpFromCache = this.regExpMap.get(pattern);
931✔
174
    if (regExpFromCache !== undefined) {
931✔
175
      return regExpFromCache;
904✔
176
    }
904✔
177
    const regExpNew = new RegExp(pattern);
27✔
178
    if (this.regExpQueue.length === this.capacity) {
931!
179
      this.regExpMap.delete(this.regExpQueue.shift());
×
180
    }
✔
181
    this.regExpMap.set(pattern, regExpNew);
27✔
182
    this.regExpQueue.push(pattern);
27✔
183
    return regExpNew;
27✔
184
  }
931✔
185
}
2✔
186

187
const chars = [' ', ',', '?', '!', ';'];
2✔
188
// We cache RegExps to improve performance with React Native Android, which has poor RegExp initialization performance.
2✔
189
// Capacity of 20 should be plenty, as nsSeparator/keySeparator don't tend to vary much across calls.
2✔
190
const looksLikeObjectPathRegExpCache = new RegExpCache(20);
2✔
191

192
export const looksLikeObjectPath = (key, nsSeparator, keySeparator) => {
2✔
193
  nsSeparator = nsSeparator || '';
931✔
194
  keySeparator = keySeparator || '';
931✔
195
  const possibleChars = chars.filter(
931✔
196
    (c) => nsSeparator.indexOf(c) < 0 && keySeparator.indexOf(c) < 0,
931✔
197
  );
931✔
198
  if (possibleChars.length === 0) return true;
931!
199
  const r = looksLikeObjectPathRegExpCache.getRegExp(
931✔
200
    `(${possibleChars.map((c) => (c === '?' ? '\\?' : c)).join('|')})`,
931✔
201
  );
931✔
202
  let matched = !r.test(key);
931✔
203
  if (!matched) {
931✔
204
    const ki = key.indexOf(keySeparator);
50✔
205
    if (ki > 0 && !r.test(key.substring(0, ki))) {
50✔
206
      matched = true;
4✔
207
    }
4✔
208
  }
50✔
209
  return matched;
931✔
210
};
931✔
211

212
/**
2✔
213
 * Given
2✔
214
 *
2✔
215
 * 1. a top level object obj, and
2✔
216
 * 2. a path to a deeply nested string or object within it
2✔
217
 *
2✔
218
 * Find and return that deeply nested string or object. The caveat is that the keys of objects within the nesting chain
2✔
219
 * may contain period characters. Therefore, we need to DFS and explore all possible keys at each step until we find the
2✔
220
 * deeply nested string or object.
2✔
221
 */
2✔
222
export const deepFind = (obj, path, keySeparator = '.') => {
2✔
223
  if (!obj) return undefined;
846✔
224
  if (obj[path]) {
846✔
225
    if (!Object.prototype.hasOwnProperty.call(obj, path)) return undefined;
21✔
226
    return obj[path];
7✔
227
  }
7✔
228
  const tokens = path.split(keySeparator);
566✔
229
  let current = obj;
566✔
230
  for (let i = 0; i < tokens.length; ) {
826✔
231
    if (!current || typeof current !== 'object') {
1,135✔
232
      return undefined;
517✔
233
    }
517✔
234
    let next;
618✔
235
    let nextPath = '';
618✔
236
    for (let j = i; j < tokens.length; ++j) {
935✔
237
      if (j !== i) {
671✔
238
        nextPath += keySeparator;
53✔
239
      }
53✔
240
      nextPath += tokens[j];
671✔
241
      next = current[nextPath];
671✔
242
      if (next !== undefined) {
671✔
243
        if (['string', 'number', 'boolean'].indexOf(typeof next) > -1 && j < tokens.length - 1) {
127✔
244
          continue;
26✔
245
        }
26✔
246
        i += j - i + 1;
101✔
247
        break;
101✔
248
      }
101✔
249
    }
671✔
250
    current = next;
618✔
251
  }
618✔
252
  return current;
49✔
253
};
49✔
254

255
export const getCleanedCode = (code) => code?.replace('_', '-');
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc