symlink-paths.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. 'use strict'
  2. const path = require('path')
  3. const fs = require('../fs')
  4. const { pathExists } = require('../path-exists')
  5. const u = require('universalify').fromPromise
  6. /**
  7. * Function that returns two types of paths, one relative to symlink, and one
  8. * relative to the current working directory. Checks if path is absolute or
  9. * relative. If the path is relative, this function checks if the path is
  10. * relative to symlink or relative to current working directory. This is an
  11. * initiative to find a smarter `srcpath` to supply when building symlinks.
  12. * This allows you to determine which path to use out of one of three possible
  13. * types of source paths. The first is an absolute path. This is detected by
  14. * `path.isAbsolute()`. When an absolute path is provided, it is checked to
  15. * see if it exists. If it does it's used, if not an error is returned
  16. * (callback)/ thrown (sync). The other two options for `srcpath` are a
  17. * relative url. By default Node's `fs.symlink` works by creating a symlink
  18. * using `dstpath` and expects the `srcpath` to be relative to the newly
  19. * created symlink. If you provide a `srcpath` that does not exist on the file
  20. * system it results in a broken symlink. To minimize this, the function
  21. * checks to see if the 'relative to symlink' source file exists, and if it
  22. * does it will use it. If it does not, it checks if there's a file that
  23. * exists that is relative to the current working directory, if does its used.
  24. * This preserves the expectations of the original fs.symlink spec and adds
  25. * the ability to pass in `relative to current working direcotry` paths.
  26. */
  27. async function symlinkPaths (srcpath, dstpath) {
  28. if (path.isAbsolute(srcpath)) {
  29. try {
  30. await fs.lstat(srcpath)
  31. } catch (err) {
  32. err.message = err.message.replace('lstat', 'ensureSymlink')
  33. throw err
  34. }
  35. return {
  36. toCwd: srcpath,
  37. toDst: srcpath
  38. }
  39. }
  40. const dstdir = path.dirname(dstpath)
  41. const relativeToDst = path.join(dstdir, srcpath)
  42. const exists = await pathExists(relativeToDst)
  43. if (exists) {
  44. return {
  45. toCwd: relativeToDst,
  46. toDst: srcpath
  47. }
  48. }
  49. try {
  50. await fs.lstat(srcpath)
  51. } catch (err) {
  52. err.message = err.message.replace('lstat', 'ensureSymlink')
  53. throw err
  54. }
  55. return {
  56. toCwd: srcpath,
  57. toDst: path.relative(dstdir, srcpath)
  58. }
  59. }
  60. function symlinkPathsSync (srcpath, dstpath) {
  61. if (path.isAbsolute(srcpath)) {
  62. const exists = fs.existsSync(srcpath)
  63. if (!exists) throw new Error('absolute srcpath does not exist')
  64. return {
  65. toCwd: srcpath,
  66. toDst: srcpath
  67. }
  68. }
  69. const dstdir = path.dirname(dstpath)
  70. const relativeToDst = path.join(dstdir, srcpath)
  71. const exists = fs.existsSync(relativeToDst)
  72. if (exists) {
  73. return {
  74. toCwd: relativeToDst,
  75. toDst: srcpath
  76. }
  77. }
  78. const srcExists = fs.existsSync(srcpath)
  79. if (!srcExists) throw new Error('relative srcpath does not exist')
  80. return {
  81. toCwd: srcpath,
  82. toDst: path.relative(dstdir, srcpath)
  83. }
  84. }
  85. module.exports = {
  86. symlinkPaths: u(symlinkPaths),
  87. symlinkPathsSync
  88. }