utils.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. "use strict";
  2. const {
  3. resolve
  4. } = require('path');
  5. const {
  6. statSync
  7. } = require('fs');
  8. const normalizePath = require('normalize-path');
  9. /**
  10. * @template T
  11. * @param {T} value
  12. * @return {
  13. T extends (null | undefined)
  14. ? []
  15. : T extends string
  16. ? [string]
  17. : T extends readonly unknown[]
  18. ? T
  19. : T extends Iterable<infer T>
  20. ? T[]
  21. : [T]
  22. }
  23. */
  24. /* istanbul ignore next */
  25. function arrify(value) {
  26. // eslint-disable-next-line no-undefined
  27. if (value === null || value === undefined) {
  28. // @ts-ignore
  29. return [];
  30. }
  31. if (Array.isArray(value)) {
  32. // @ts-ignore
  33. return value;
  34. }
  35. if (typeof value === 'string') {
  36. // @ts-ignore
  37. return [value];
  38. } // @ts-ignore
  39. if (typeof value[Symbol.iterator] === 'function') {
  40. // @ts-ignore
  41. return [...value];
  42. } // @ts-ignore
  43. return [value];
  44. }
  45. /**
  46. * @param {string|string[]} files
  47. * @param {string} context
  48. * @returns {string[]}
  49. */
  50. function parseFiles(files, context) {
  51. return arrify(files).map((
  52. /** @type {string} */
  53. file) => normalizePath(resolve(context, file)));
  54. }
  55. /**
  56. * @param {string|string[]} patterns
  57. * @param {string|string[]} extensions
  58. * @returns {string[]}
  59. */
  60. function parseFoldersToGlobs(patterns, extensions = []) {
  61. const extensionsList = arrify(extensions);
  62. const [prefix, postfix] = extensionsList.length > 1 ? ['{', '}'] : ['', ''];
  63. const extensionsGlob = extensionsList.map((
  64. /** @type {string} */
  65. extension) => extension.replace(/^\./u, '')).join(',');
  66. return arrify(patterns).map((
  67. /** @type {string} */
  68. pattern) => {
  69. try {
  70. // The patterns are absolute because they are prepended with the context.
  71. const stats = statSync(pattern);
  72. /* istanbul ignore else */
  73. if (stats.isDirectory()) {
  74. return pattern.replace(/[/\\]*?$/u, `/**${extensionsGlob ? `/*.${prefix + extensionsGlob + postfix}` : ''}`);
  75. }
  76. } catch (_) {// Return the pattern as is on error.
  77. }
  78. return pattern;
  79. });
  80. }
  81. /**
  82. * @param {string} _ key, but unused
  83. * @param {any} value
  84. */
  85. const jsonStringifyReplacerSortKeys = (_, value) => {
  86. /**
  87. * @param {{ [x: string]: any; }} sorted
  88. * @param {string | number} key
  89. */
  90. const insert = (sorted, key) => {
  91. // eslint-disable-next-line no-param-reassign
  92. sorted[key] = value[key];
  93. return sorted;
  94. };
  95. return value instanceof Object && !(value instanceof Array) ? Object.keys(value).sort().reduce(insert, {}) : value;
  96. };
  97. module.exports = {
  98. arrify,
  99. parseFiles,
  100. parseFoldersToGlobs,
  101. jsonStringifyReplacerSortKeys
  102. };