Dieses Repository beinhaltet HTML- und Javascript Code zur einer NotizenWebApp auf Basis von Web Storage. Zudem sind Mocha/Chai Tests im Browser enthalten. https://meinenotizen.netlify.app/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

utils.js 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. 'use strict';
  2. /**
  3. * Various utility functions used throughout Mocha's codebase.
  4. * @module utils
  5. */
  6. /**
  7. * Module dependencies.
  8. */
  9. var fs = require('fs');
  10. var path = require('path');
  11. var util = require('util');
  12. var glob = require('glob');
  13. var he = require('he');
  14. var errors = require('./errors');
  15. var createNoFilesMatchPatternError = errors.createNoFilesMatchPatternError;
  16. var createMissingArgumentError = errors.createMissingArgumentError;
  17. var assign = (exports.assign = require('object.assign').getPolyfill());
  18. /**
  19. * Inherit the prototype methods from one constructor into another.
  20. *
  21. * @param {function} ctor - Constructor function which needs to inherit the
  22. * prototype.
  23. * @param {function} superCtor - Constructor function to inherit prototype from.
  24. * @throws {TypeError} if either constructor is null, or if super constructor
  25. * lacks a prototype.
  26. */
  27. exports.inherits = util.inherits;
  28. /**
  29. * Escape special characters in the given string of html.
  30. *
  31. * @private
  32. * @param {string} html
  33. * @return {string}
  34. */
  35. exports.escape = function(html) {
  36. return he.encode(String(html), {useNamedReferences: false});
  37. };
  38. /**
  39. * Test if the given obj is type of string.
  40. *
  41. * @private
  42. * @param {Object} obj
  43. * @return {boolean}
  44. */
  45. exports.isString = function(obj) {
  46. return typeof obj === 'string';
  47. };
  48. /**
  49. * Compute a slug from the given `str`.
  50. *
  51. * @private
  52. * @param {string} str
  53. * @return {string}
  54. */
  55. exports.slug = function(str) {
  56. return str
  57. .toLowerCase()
  58. .replace(/\s+/g, '-')
  59. .replace(/[^-\w]/g, '')
  60. .replace(/-{2,}/g, '-');
  61. };
  62. /**
  63. * Strip the function definition from `str`, and re-indent for pre whitespace.
  64. *
  65. * @param {string} str
  66. * @return {string}
  67. */
  68. exports.clean = function(str) {
  69. str = str
  70. .replace(/\r\n?|[\n\u2028\u2029]/g, '\n')
  71. .replace(/^\uFEFF/, '')
  72. // (traditional)-> space/name parameters body (lambda)-> parameters body multi-statement/single keep body content
  73. .replace(
  74. /^function(?:\s*|\s+[^(]*)\([^)]*\)\s*\{((?:.|\n)*?)\s*\}$|^\([^)]*\)\s*=>\s*(?:\{((?:.|\n)*?)\s*\}|((?:.|\n)*))$/,
  75. '$1$2$3'
  76. );
  77. var spaces = str.match(/^\n?( *)/)[1].length;
  78. var tabs = str.match(/^\n?(\t*)/)[1].length;
  79. var re = new RegExp(
  80. '^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs || spaces) + '}',
  81. 'gm'
  82. );
  83. str = str.replace(re, '');
  84. return str.trim();
  85. };
  86. /**
  87. * Parse the given `qs`.
  88. *
  89. * @private
  90. * @param {string} qs
  91. * @return {Object}
  92. */
  93. exports.parseQuery = function(qs) {
  94. return qs
  95. .replace('?', '')
  96. .split('&')
  97. .reduce(function(obj, pair) {
  98. var i = pair.indexOf('=');
  99. var key = pair.slice(0, i);
  100. var val = pair.slice(++i);
  101. // Due to how the URLSearchParams API treats spaces
  102. obj[key] = decodeURIComponent(val.replace(/\+/g, '%20'));
  103. return obj;
  104. }, {});
  105. };
  106. /**
  107. * Highlight the given string of `js`.
  108. *
  109. * @private
  110. * @param {string} js
  111. * @return {string}
  112. */
  113. function highlight(js) {
  114. return js
  115. .replace(/</g, '&lt;')
  116. .replace(/>/g, '&gt;')
  117. .replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
  118. .replace(/('.*?')/gm, '<span class="string">$1</span>')
  119. .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
  120. .replace(/(\d+)/gm, '<span class="number">$1</span>')
  121. .replace(
  122. /\bnew[ \t]+(\w+)/gm,
  123. '<span class="keyword">new</span> <span class="init">$1</span>'
  124. )
  125. .replace(
  126. /\b(function|new|throw|return|var|if|else)\b/gm,
  127. '<span class="keyword">$1</span>'
  128. );
  129. }
  130. /**
  131. * Highlight the contents of tag `name`.
  132. *
  133. * @private
  134. * @param {string} name
  135. */
  136. exports.highlightTags = function(name) {
  137. var code = document.getElementById('mocha').getElementsByTagName(name);
  138. for (var i = 0, len = code.length; i < len; ++i) {
  139. code[i].innerHTML = highlight(code[i].innerHTML);
  140. }
  141. };
  142. /**
  143. * If a value could have properties, and has none, this function is called,
  144. * which returns a string representation of the empty value.
  145. *
  146. * Functions w/ no properties return `'[Function]'`
  147. * Arrays w/ length === 0 return `'[]'`
  148. * Objects w/ no properties return `'{}'`
  149. * All else: return result of `value.toString()`
  150. *
  151. * @private
  152. * @param {*} value The value to inspect.
  153. * @param {string} typeHint The type of the value
  154. * @returns {string}
  155. */
  156. function emptyRepresentation(value, typeHint) {
  157. switch (typeHint) {
  158. case 'function':
  159. return '[Function]';
  160. case 'object':
  161. return '{}';
  162. case 'array':
  163. return '[]';
  164. default:
  165. return value.toString();
  166. }
  167. }
  168. /**
  169. * Takes some variable and asks `Object.prototype.toString()` what it thinks it
  170. * is.
  171. *
  172. * @private
  173. * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
  174. * @param {*} value The value to test.
  175. * @returns {string} Computed type
  176. * @example
  177. * type({}) // 'object'
  178. * type([]) // 'array'
  179. * type(1) // 'number'
  180. * type(false) // 'boolean'
  181. * type(Infinity) // 'number'
  182. * type(null) // 'null'
  183. * type(new Date()) // 'date'
  184. * type(/foo/) // 'regexp'
  185. * type('type') // 'string'
  186. * type(global) // 'global'
  187. * type(new String('foo') // 'object'
  188. */
  189. var type = (exports.type = function type(value) {
  190. if (value === undefined) {
  191. return 'undefined';
  192. } else if (value === null) {
  193. return 'null';
  194. } else if (Buffer.isBuffer(value)) {
  195. return 'buffer';
  196. }
  197. return Object.prototype.toString
  198. .call(value)
  199. .replace(/^\[.+\s(.+?)]$/, '$1')
  200. .toLowerCase();
  201. });
  202. /**
  203. * Stringify `value`. Different behavior depending on type of value:
  204. *
  205. * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively.
  206. * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes.
  207. * - If `value` is an *empty* object, function, or array, return result of function
  208. * {@link emptyRepresentation}.
  209. * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of
  210. * JSON.stringify().
  211. *
  212. * @private
  213. * @see exports.type
  214. * @param {*} value
  215. * @return {string}
  216. */
  217. exports.stringify = function(value) {
  218. var typeHint = type(value);
  219. if (!~['object', 'array', 'function'].indexOf(typeHint)) {
  220. if (typeHint === 'buffer') {
  221. var json = Buffer.prototype.toJSON.call(value);
  222. // Based on the toJSON result
  223. return jsonStringify(
  224. json.data && json.type ? json.data : json,
  225. 2
  226. ).replace(/,(\n|$)/g, '$1');
  227. }
  228. // IE7/IE8 has a bizarre String constructor; needs to be coerced
  229. // into an array and back to obj.
  230. if (typeHint === 'string' && typeof value === 'object') {
  231. value = value.split('').reduce(function(acc, char, idx) {
  232. acc[idx] = char;
  233. return acc;
  234. }, {});
  235. typeHint = 'object';
  236. } else {
  237. return jsonStringify(value);
  238. }
  239. }
  240. for (var prop in value) {
  241. if (Object.prototype.hasOwnProperty.call(value, prop)) {
  242. return jsonStringify(
  243. exports.canonicalize(value, null, typeHint),
  244. 2
  245. ).replace(/,(\n|$)/g, '$1');
  246. }
  247. }
  248. return emptyRepresentation(value, typeHint);
  249. };
  250. /**
  251. * like JSON.stringify but more sense.
  252. *
  253. * @private
  254. * @param {Object} object
  255. * @param {number=} spaces
  256. * @param {number=} depth
  257. * @returns {*}
  258. */
  259. function jsonStringify(object, spaces, depth) {
  260. if (typeof spaces === 'undefined') {
  261. // primitive types
  262. return _stringify(object);
  263. }
  264. depth = depth || 1;
  265. var space = spaces * depth;
  266. var str = Array.isArray(object) ? '[' : '{';
  267. var end = Array.isArray(object) ? ']' : '}';
  268. var length =
  269. typeof object.length === 'number'
  270. ? object.length
  271. : Object.keys(object).length;
  272. // `.repeat()` polyfill
  273. function repeat(s, n) {
  274. return new Array(n).join(s);
  275. }
  276. function _stringify(val) {
  277. switch (type(val)) {
  278. case 'null':
  279. case 'undefined':
  280. val = '[' + val + ']';
  281. break;
  282. case 'array':
  283. case 'object':
  284. val = jsonStringify(val, spaces, depth + 1);
  285. break;
  286. case 'boolean':
  287. case 'regexp':
  288. case 'symbol':
  289. case 'number':
  290. val =
  291. val === 0 && 1 / val === -Infinity // `-0`
  292. ? '-0'
  293. : val.toString();
  294. break;
  295. case 'date':
  296. var sDate = isNaN(val.getTime()) ? val.toString() : val.toISOString();
  297. val = '[Date: ' + sDate + ']';
  298. break;
  299. case 'buffer':
  300. var json = val.toJSON();
  301. // Based on the toJSON result
  302. json = json.data && json.type ? json.data : json;
  303. val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']';
  304. break;
  305. default:
  306. val =
  307. val === '[Function]' || val === '[Circular]'
  308. ? val
  309. : JSON.stringify(val); // string
  310. }
  311. return val;
  312. }
  313. for (var i in object) {
  314. if (!Object.prototype.hasOwnProperty.call(object, i)) {
  315. continue; // not my business
  316. }
  317. --length;
  318. str +=
  319. '\n ' +
  320. repeat(' ', space) +
  321. (Array.isArray(object) ? '' : '"' + i + '": ') + // key
  322. _stringify(object[i]) + // value
  323. (length ? ',' : ''); // comma
  324. }
  325. return (
  326. str +
  327. // [], {}
  328. (str.length !== 1 ? '\n' + repeat(' ', --space) + end : end)
  329. );
  330. }
  331. /**
  332. * Return a new Thing that has the keys in sorted order. Recursive.
  333. *
  334. * If the Thing...
  335. * - has already been seen, return string `'[Circular]'`
  336. * - is `undefined`, return string `'[undefined]'`
  337. * - is `null`, return value `null`
  338. * - is some other primitive, return the value
  339. * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method
  340. * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
  341. * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`
  342. *
  343. * @private
  344. * @see {@link exports.stringify}
  345. * @param {*} value Thing to inspect. May or may not have properties.
  346. * @param {Array} [stack=[]] Stack of seen values
  347. * @param {string} [typeHint] Type hint
  348. * @return {(Object|Array|Function|string|undefined)}
  349. */
  350. exports.canonicalize = function canonicalize(value, stack, typeHint) {
  351. var canonicalizedObj;
  352. /* eslint-disable no-unused-vars */
  353. var prop;
  354. /* eslint-enable no-unused-vars */
  355. typeHint = typeHint || type(value);
  356. function withStack(value, fn) {
  357. stack.push(value);
  358. fn();
  359. stack.pop();
  360. }
  361. stack = stack || [];
  362. if (stack.indexOf(value) !== -1) {
  363. return '[Circular]';
  364. }
  365. switch (typeHint) {
  366. case 'undefined':
  367. case 'buffer':
  368. case 'null':
  369. canonicalizedObj = value;
  370. break;
  371. case 'array':
  372. withStack(value, function() {
  373. canonicalizedObj = value.map(function(item) {
  374. return exports.canonicalize(item, stack);
  375. });
  376. });
  377. break;
  378. case 'function':
  379. /* eslint-disable guard-for-in */
  380. for (prop in value) {
  381. canonicalizedObj = {};
  382. break;
  383. }
  384. /* eslint-enable guard-for-in */
  385. if (!canonicalizedObj) {
  386. canonicalizedObj = emptyRepresentation(value, typeHint);
  387. break;
  388. }
  389. /* falls through */
  390. case 'object':
  391. canonicalizedObj = canonicalizedObj || {};
  392. withStack(value, function() {
  393. Object.keys(value)
  394. .sort()
  395. .forEach(function(key) {
  396. canonicalizedObj[key] = exports.canonicalize(value[key], stack);
  397. });
  398. });
  399. break;
  400. case 'date':
  401. case 'number':
  402. case 'regexp':
  403. case 'boolean':
  404. case 'symbol':
  405. canonicalizedObj = value;
  406. break;
  407. default:
  408. canonicalizedObj = value + '';
  409. }
  410. return canonicalizedObj;
  411. };
  412. /**
  413. * Determines if pathname has a matching file extension.
  414. *
  415. * @private
  416. * @param {string} pathname - Pathname to check for match.
  417. * @param {string[]} exts - List of file extensions (sans period).
  418. * @return {boolean} whether file extension matches.
  419. * @example
  420. * hasMatchingExtname('foo.html', ['js', 'css']); // => false
  421. */
  422. function hasMatchingExtname(pathname, exts) {
  423. var suffix = path.extname(pathname).slice(1);
  424. return exts.some(function(element) {
  425. return suffix === element;
  426. });
  427. }
  428. /**
  429. * Determines if pathname would be a "hidden" file (or directory) on UN*X.
  430. *
  431. * @description
  432. * On UN*X, pathnames beginning with a full stop (aka dot) are hidden during
  433. * typical usage. Dotfiles, plain-text configuration files, are prime examples.
  434. *
  435. * @see {@link http://xahlee.info/UnixResource_dir/writ/unix_origin_of_dot_filename.html|Origin of Dot File Names}
  436. *
  437. * @private
  438. * @param {string} pathname - Pathname to check for match.
  439. * @return {boolean} whether pathname would be considered a hidden file.
  440. * @example
  441. * isHiddenOnUnix('.profile'); // => true
  442. */
  443. function isHiddenOnUnix(pathname) {
  444. return path.basename(pathname)[0] === '.';
  445. }
  446. /**
  447. * Lookup file names at the given `path`.
  448. *
  449. * @description
  450. * Filenames are returned in _traversal_ order by the OS/filesystem.
  451. * **Make no assumption that the names will be sorted in any fashion.**
  452. *
  453. * @public
  454. * @memberof Mocha.utils
  455. * @param {string} filepath - Base path to start searching from.
  456. * @param {string[]} [extensions=[]] - File extensions to look for.
  457. * @param {boolean} [recursive=false] - Whether to recurse into subdirectories.
  458. * @return {string[]} An array of paths.
  459. * @throws {Error} if no files match pattern.
  460. * @throws {TypeError} if `filepath` is directory and `extensions` not provided.
  461. */
  462. exports.lookupFiles = function lookupFiles(filepath, extensions, recursive) {
  463. extensions = extensions || [];
  464. recursive = recursive || false;
  465. var files = [];
  466. var stat;
  467. if (!fs.existsSync(filepath)) {
  468. var pattern;
  469. if (glob.hasMagic(filepath)) {
  470. // Handle glob as is without extensions
  471. pattern = filepath;
  472. } else {
  473. // glob pattern e.g. 'filepath+(.js|.ts)'
  474. var strExtensions = extensions
  475. .map(function(v) {
  476. return '.' + v;
  477. })
  478. .join('|');
  479. pattern = filepath + '+(' + strExtensions + ')';
  480. }
  481. files = glob.sync(pattern, {nodir: true});
  482. if (!files.length) {
  483. throw createNoFilesMatchPatternError(
  484. 'Cannot find any files matching pattern ' + exports.dQuote(filepath),
  485. filepath
  486. );
  487. }
  488. return files;
  489. }
  490. // Handle file
  491. try {
  492. stat = fs.statSync(filepath);
  493. if (stat.isFile()) {
  494. return filepath;
  495. }
  496. } catch (err) {
  497. // ignore error
  498. return;
  499. }
  500. // Handle directory
  501. fs.readdirSync(filepath).forEach(function(dirent) {
  502. var pathname = path.join(filepath, dirent);
  503. var stat;
  504. try {
  505. stat = fs.statSync(pathname);
  506. if (stat.isDirectory()) {
  507. if (recursive) {
  508. files = files.concat(lookupFiles(pathname, extensions, recursive));
  509. }
  510. return;
  511. }
  512. } catch (err) {
  513. // ignore error
  514. return;
  515. }
  516. if (!extensions.length) {
  517. throw createMissingArgumentError(
  518. util.format(
  519. 'Argument %s required when argument %s is a directory',
  520. exports.sQuote('extensions'),
  521. exports.sQuote('filepath')
  522. ),
  523. 'extensions',
  524. 'array'
  525. );
  526. }
  527. if (
  528. !stat.isFile() ||
  529. !hasMatchingExtname(pathname, extensions) ||
  530. isHiddenOnUnix(pathname)
  531. ) {
  532. return;
  533. }
  534. files.push(pathname);
  535. });
  536. return files;
  537. };
  538. /**
  539. * process.emitWarning or a polyfill
  540. * @see https://nodejs.org/api/process.html#process_process_emitwarning_warning_options
  541. * @ignore
  542. */
  543. function emitWarning(msg, type) {
  544. if (process.emitWarning) {
  545. process.emitWarning(msg, type);
  546. } else {
  547. process.nextTick(function() {
  548. console.warn(type + ': ' + msg);
  549. });
  550. }
  551. }
  552. /**
  553. * Show a deprecation warning. Each distinct message is only displayed once.
  554. * Ignores empty messages.
  555. *
  556. * @param {string} [msg] - Warning to print
  557. * @private
  558. */
  559. exports.deprecate = function deprecate(msg) {
  560. msg = String(msg);
  561. if (msg && !deprecate.cache[msg]) {
  562. deprecate.cache[msg] = true;
  563. emitWarning(msg, 'DeprecationWarning');
  564. }
  565. };
  566. exports.deprecate.cache = {};
  567. /**
  568. * Show a generic warning.
  569. * Ignores empty messages.
  570. *
  571. * @param {string} [msg] - Warning to print
  572. * @private
  573. */
  574. exports.warn = function warn(msg) {
  575. if (msg) {
  576. emitWarning(msg);
  577. }
  578. };
  579. /**
  580. * @summary
  581. * This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`)
  582. * @description
  583. * When invoking this function you get a filter function that get the Error.stack as an input,
  584. * and return a prettify output.
  585. * (i.e: strip Mocha and internal node functions from stack trace).
  586. * @returns {Function}
  587. */
  588. exports.stackTraceFilter = function() {
  589. // TODO: Replace with `process.browser`
  590. var is = typeof document === 'undefined' ? {node: true} : {browser: true};
  591. var slash = path.sep;
  592. var cwd;
  593. if (is.node) {
  594. cwd = exports.cwd() + slash;
  595. } else {
  596. cwd = (typeof location === 'undefined'
  597. ? window.location
  598. : location
  599. ).href.replace(/\/[^/]*$/, '/');
  600. slash = '/';
  601. }
  602. function isMochaInternal(line) {
  603. return (
  604. ~line.indexOf('node_modules' + slash + 'mocha' + slash) ||
  605. ~line.indexOf(slash + 'mocha.js') ||
  606. ~line.indexOf(slash + 'mocha.min.js')
  607. );
  608. }
  609. function isNodeInternal(line) {
  610. return (
  611. ~line.indexOf('(timers.js:') ||
  612. ~line.indexOf('(events.js:') ||
  613. ~line.indexOf('(node.js:') ||
  614. ~line.indexOf('(module.js:') ||
  615. ~line.indexOf('GeneratorFunctionPrototype.next (native)') ||
  616. false
  617. );
  618. }
  619. return function(stack) {
  620. stack = stack.split('\n');
  621. stack = stack.reduce(function(list, line) {
  622. if (isMochaInternal(line)) {
  623. return list;
  624. }
  625. if (is.node && isNodeInternal(line)) {
  626. return list;
  627. }
  628. // Clean up cwd(absolute)
  629. if (/:\d+:\d+\)?$/.test(line)) {
  630. line = line.replace('(' + cwd, '(');
  631. }
  632. list.push(line);
  633. return list;
  634. }, []);
  635. return stack.join('\n');
  636. };
  637. };
  638. /**
  639. * Crude, but effective.
  640. * @public
  641. * @param {*} value
  642. * @returns {boolean} Whether or not `value` is a Promise
  643. */
  644. exports.isPromise = function isPromise(value) {
  645. return (
  646. typeof value === 'object' &&
  647. value !== null &&
  648. typeof value.then === 'function'
  649. );
  650. };
  651. /**
  652. * Clamps a numeric value to an inclusive range.
  653. *
  654. * @param {number} value - Value to be clamped.
  655. * @param {numer[]} range - Two element array specifying [min, max] range.
  656. * @returns {number} clamped value
  657. */
  658. exports.clamp = function clamp(value, range) {
  659. return Math.min(Math.max(value, range[0]), range[1]);
  660. };
  661. /**
  662. * Single quote text by combining with undirectional ASCII quotation marks.
  663. *
  664. * @description
  665. * Provides a simple means of markup for quoting text to be used in output.
  666. * Use this to quote names of variables, methods, and packages.
  667. *
  668. * <samp>package 'foo' cannot be found</samp>
  669. *
  670. * @private
  671. * @param {string} str - Value to be quoted.
  672. * @returns {string} quoted value
  673. * @example
  674. * sQuote('n') // => 'n'
  675. */
  676. exports.sQuote = function(str) {
  677. return "'" + str + "'";
  678. };
  679. /**
  680. * Double quote text by combining with undirectional ASCII quotation marks.
  681. *
  682. * @description
  683. * Provides a simple means of markup for quoting text to be used in output.
  684. * Use this to quote names of datatypes, classes, pathnames, and strings.
  685. *
  686. * <samp>argument 'value' must be "string" or "number"</samp>
  687. *
  688. * @private
  689. * @param {string} str - Value to be quoted.
  690. * @returns {string} quoted value
  691. * @example
  692. * dQuote('number') // => "number"
  693. */
  694. exports.dQuote = function(str) {
  695. return '"' + str + '"';
  696. };
  697. /**
  698. * It's a noop.
  699. * @public
  700. */
  701. exports.noop = function() {};
  702. /**
  703. * Creates a map-like object.
  704. *
  705. * @description
  706. * A "map" is an object with no prototype, for our purposes. In some cases
  707. * this would be more appropriate than a `Map`, especially if your environment
  708. * doesn't support it. Recommended for use in Mocha's public APIs.
  709. *
  710. * @public
  711. * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map|MDN:Map}
  712. * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Custom_and_Null_objects|MDN:Object.create - Custom objects}
  713. * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign|MDN:Object.assign}
  714. * @param {...*} [obj] - Arguments to `Object.assign()`.
  715. * @returns {Object} An object with no prototype, having `...obj` properties
  716. */
  717. exports.createMap = function(obj) {
  718. return assign.apply(
  719. null,
  720. [Object.create(null)].concat(Array.prototype.slice.call(arguments))
  721. );
  722. };
  723. /**
  724. * Creates a read-only map-like object.
  725. *
  726. * @description
  727. * This differs from {@link module:utils.createMap createMap} only in that
  728. * the argument must be non-empty, because the result is frozen.
  729. *
  730. * @see {@link module:utils.createMap createMap}
  731. * @param {...*} [obj] - Arguments to `Object.assign()`.
  732. * @returns {Object} A frozen object with no prototype, having `...obj` properties
  733. * @throws {TypeError} if argument is not a non-empty object.
  734. */
  735. exports.defineConstants = function(obj) {
  736. if (type(obj) !== 'object' || !Object.keys(obj).length) {
  737. throw new TypeError('Invalid argument; expected a non-empty object');
  738. }
  739. return Object.freeze(exports.createMap(obj));
  740. };
  741. /**
  742. * Whether current version of Node support ES modules
  743. *
  744. * @description
  745. * Versions prior to 10 did not support ES Modules, and version 10 has an old incompatibile version of ESM.
  746. * This function returns whether Node.JS has ES Module supports that is compatible with Mocha's needs,
  747. * which is version >=12.11.
  748. *
  749. * @returns {Boolean} whether the current version of Node.JS supports ES Modules in a way that is compatible with Mocha
  750. */
  751. exports.supportsEsModules = function() {
  752. if (!process.browser && process.versions && process.versions.node) {
  753. var versionFields = process.versions.node.split('.');
  754. var major = +versionFields[0];
  755. var minor = +versionFields[1];
  756. if (major >= 13 || (major === 12 && minor >= 11)) {
  757. return true;
  758. }
  759. }
  760. };
  761. /**
  762. * Returns current working directory
  763. *
  764. * Wrapper around `process.cwd()` for isolation
  765. * @private
  766. */
  767. exports.cwd = function cwd() {
  768. return process.cwd();
  769. };