Source

index.ts

  1. import { join, basename, sep } from 'path';
  2. import { mkdtemp as fsmkdtemp } from 'fs';
  3. import { homedir, tmpdir } from 'os';
  4. import { FSDir } from './fs-dir.class';
  5. import { FSFile } from './fs-file.class';
  6. import { FSAsyncIterable } from './fs-async-iterable.class';
  7. /**
  8. * Represent dirent which can be converted to FSDir or FSFile.
  9. */
  10. export class FSDirent {
  11. constructor(public readonly path: string) {}
  12. public readonly name = basename(this.path);
  13. /**
  14. * Use to work with current path as file system directory.
  15. * @return {FSDir}
  16. */
  17. public asDir(): FSDir {
  18. return new FSDir(this.path);
  19. }
  20. /**
  21. * Use to work with current path as file system file
  22. * @return {FSFile}
  23. */
  24. public asFile(): FSFile {
  25. return new FSFile(this.path);
  26. }
  27. }
  28. export type FSPathType = {
  29. (): FSDirent;
  30. [key: string]: FSPathType;
  31. };
  32. /**
  33. * Creates path to filesystem object. Can be chained with any
  34. * key name wich act as path segment.
  35. * WARNING: Do not return FSPath with Promise resolve. This leads to unexpected behavior.
  36. * @return {FSDirent}
  37. *
  38. * @example
  39. * FSPath(__dirname).node_modules //work as path.join(__dirname, "node_modules")
  40. * FSPath(__dirname)["package.json"] //work as path.join(__dirname, "package.json")
  41. * // When path completed you can get further operation to call it as function.
  42. * FSPath(__dirname).node_modules().asDir() //At this point you can use FSDir
  43. * FSPath(__dirname)["package.json"]().asFile() //At this point you can use FSFile
  44. *
  45. * @param {string} path - start path
  46. */
  47. export const FSPath = function(path: string): FSPathType {
  48. return new Proxy(() => new FSDirent(path), {
  49. get: (_, key: string) => FSPath(join(path, key)),
  50. }) as FSPathType;
  51. };
  52. /**
  53. * Shortcut for FSPath(process.cwd())
  54. */
  55. export const cwd = FSPath(process.cwd());
  56. /**
  57. * Shortcut for FSPath(__dirname)
  58. */
  59. export const dirname = FSPath(__dirname);
  60. /**
  61. * Shortcut for FSPath(homedir())
  62. */
  63. export const home = FSPath(homedir());
  64. /**
  65. * Shortcut for FSPath(tmpdir())
  66. */
  67. export const tmp = FSPath(tmpdir());
  68. /**
  69. * Creates a unique temporary directory inside os tmpdir.
  70. * Generates six random characters to be appended behind a required prefix to create a unique temporary directory.
  71. * Due to platform inconsistencies, avoid trailing X characters in prefix.
  72. * Some platforms, notably the BSDs, can return more than six random characters,
  73. * and replace trailing X characters in prefix with random characters.
  74. * The created directory path is passed as a string to the callback's second parameter.
  75. * @param prefix
  76. */
  77. export const mkdtemp = async (prefix?: string) => {
  78. const temppath = await new Promise<FSDir>((resolve, reject) => {
  79. fsmkdtemp(prefix ? join(tmpdir(), prefix) : `${tmpdir()}${sep}`, (err, path) => {
  80. if (err) return reject(err);
  81. const dir = FSPath(path)().asDir();
  82. resolve(dir);
  83. });
  84. });
  85. return temppath;
  86. };
  87. /**
  88. * Returns FSPath for environment variable.
  89. * If environment variable whith given name not exists,
  90. * Then return FSPath for provided fallback value,
  91. * if no fallback value provided then returns nothing
  92. * @param {string} envVariableName
  93. * @param {string} fallbackValue
  94. */
  95. export const envPath = (envVariableName: string, fallbackValue?: string): FSPathType => {
  96. let envVar = process.env[envVariableName];
  97. if (envVar) return FSPath(envVar);
  98. if (fallbackValue) return FSPath(fallbackValue);
  99. throw Error(`Not found process.env[${envVariableName}] and fallback value didnt provided.`);
  100. };
  101. /**
  102. * Returns FSAsyncIterator that
  103. * takes in a starting index and ending index then iterates
  104. * thru all integers from start to end
  105. * @param from - start index
  106. * @param to - end index
  107. */
  108. export const range = (from: number, to: number) => {
  109. const rangeGenerator = async function*() {
  110. for (let index = from; index <= to; index++) {
  111. yield index;
  112. }
  113. };
  114. return new FSAsyncIterable(rangeGenerator());
  115. };