index.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _fs = _interopRequireDefault(require("fs"));
  7. var _path = _interopRequireDefault(require("path"));
  8. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  9. const readFileSync = fp => {
  10. return _fs.default.readFileSync(fp, 'utf8');
  11. };
  12. const pathExists = fp => new Promise(resolve => {
  13. _fs.default.access(fp, err => {
  14. resolve(!err);
  15. });
  16. });
  17. const pathExistsSync = _fs.default.existsSync;
  18. class JoyCon {
  19. constructor({
  20. files,
  21. cwd = process.cwd(),
  22. stopDir,
  23. packageKey,
  24. parseJSON = JSON.parse
  25. } = {}) {
  26. this.options = {
  27. files,
  28. cwd,
  29. stopDir,
  30. packageKey,
  31. parseJSON
  32. };
  33. this.existsCache = new Map();
  34. this.loaders = new Set();
  35. this.packageJsonCache = new Map();
  36. this.loadCache = new Map();
  37. }
  38. addLoader(loader) {
  39. this.loaders.add(loader);
  40. return this;
  41. }
  42. removeLoader(name) {
  43. for (const loader of this.loaders) {
  44. if (name && loader.name === name) {
  45. this.loaders.delete(loader);
  46. }
  47. }
  48. return this;
  49. }
  50. async recusivelyResolve(options) {
  51. if (options.cwd === options.stopDir || _path.default.basename(options.cwd) === 'node_modules') {
  52. return null;
  53. }
  54. for (const filename of options.files) {
  55. const file = _path.default.resolve(options.cwd, filename);
  56. const exists = process.env.NODE_ENV !== 'test' && this.existsCache.has(file) ? this.existsCache.get(file) : await pathExists(file);
  57. this.existsCache.set(file, exists);
  58. if (exists) {
  59. if (!options.packageKey || _path.default.basename(file) !== 'package.json') {
  60. return file;
  61. }
  62. const data = require(file);
  63. delete require.cache[file];
  64. const hasPackageKey = Object.prototype.hasOwnProperty.call(data, options.packageKey);
  65. if (hasPackageKey) {
  66. this.packageJsonCache.set(file, data);
  67. return file;
  68. }
  69. }
  70. continue;
  71. }
  72. return this.recusivelyResolve(Object.assign({}, options, {
  73. cwd: _path.default.dirname(options.cwd)
  74. }));
  75. }
  76. recusivelyResolveSync(options) {
  77. if (options.cwd === options.stopDir || _path.default.basename(options.cwd) === 'node_modules') {
  78. return null;
  79. }
  80. for (const filename of options.files) {
  81. const file = _path.default.resolve(options.cwd, filename);
  82. const exists = process.env.NODE_ENV !== 'test' && this.existsCache.has(file) ? this.existsCache.get(file) : pathExistsSync(file);
  83. this.existsCache.set(file, exists);
  84. if (exists) {
  85. if (!options.packageKey || _path.default.basename(file) !== 'package.json') {
  86. return file;
  87. }
  88. const data = require(file);
  89. delete require.cache[file];
  90. const hasPackageKey = Object.prototype.hasOwnProperty.call(data, options.packageKey);
  91. if (hasPackageKey) {
  92. this.packageJsonCache.set(file, data);
  93. return file;
  94. }
  95. }
  96. continue;
  97. }
  98. return this.recusivelyResolveSync(Object.assign({}, options, {
  99. cwd: _path.default.dirname(options.cwd)
  100. }));
  101. }
  102. async resolve(...args) {
  103. const options = this.normalizeOptions(args);
  104. return this.recusivelyResolve(options);
  105. }
  106. resolveSync(...args) {
  107. const options = this.normalizeOptions(args);
  108. return this.recusivelyResolveSync(options);
  109. }
  110. runLoaderSync(loader, filepath) {
  111. return loader.loadSync(filepath);
  112. }
  113. runLoader(loader, filepath) {
  114. if (!loader.load) return loader.loadSync(filepath);
  115. return loader.load(filepath);
  116. }
  117. async load(...args) {
  118. const options = this.normalizeOptions(args);
  119. const filepath = await this.recusivelyResolve(options);
  120. if (filepath) {
  121. const defaultLoader = {
  122. test: /\.+/,
  123. loadSync: filepath => {
  124. const extname = _path.default.extname(filepath).slice(1);
  125. if (extname === 'js' || extname === 'cjs') {
  126. delete require.cache[filepath];
  127. return require(filepath);
  128. }
  129. if (this.packageJsonCache.has(filepath)) {
  130. return this.packageJsonCache.get(filepath)[options.packageKey];
  131. }
  132. const data = this.options.parseJSON(readFileSync(filepath));
  133. return data;
  134. }
  135. };
  136. const loader = this.findLoader(filepath) || defaultLoader;
  137. let data;
  138. if (this.loadCache.has(filepath)) {
  139. data = this.loadCache.get(filepath);
  140. } else {
  141. data = await this.runLoader(loader, filepath);
  142. this.loadCache.set(filepath, data);
  143. }
  144. return {
  145. path: filepath,
  146. data
  147. };
  148. }
  149. return {};
  150. }
  151. loadSync(...args) {
  152. const options = this.normalizeOptions(args);
  153. const filepath = this.recusivelyResolveSync(options);
  154. if (filepath) {
  155. const defaultLoader = {
  156. test: /\.+/,
  157. loadSync: filepath => {
  158. const extname = _path.default.extname(filepath).slice(1);
  159. if (extname === 'js' || extname === 'cjs') {
  160. delete require.cache[filepath];
  161. return require(filepath);
  162. }
  163. if (this.packageJsonCache.has(filepath)) {
  164. return this.packageJsonCache.get(filepath)[options.packageKey];
  165. }
  166. const data = this.options.parseJSON(readFileSync(filepath));
  167. return data;
  168. }
  169. };
  170. const loader = this.findLoader(filepath) || defaultLoader;
  171. let data;
  172. if (this.loadCache.has(filepath)) {
  173. data = this.loadCache.get(filepath);
  174. } else {
  175. data = this.runLoaderSync(loader, filepath);
  176. this.loadCache.set(filepath, data);
  177. }
  178. return {
  179. path: filepath,
  180. data
  181. };
  182. }
  183. return {};
  184. }
  185. findLoader(filepath) {
  186. for (const loader of this.loaders) {
  187. if (loader.test && loader.test.test(filepath)) {
  188. return loader;
  189. }
  190. }
  191. return null;
  192. }
  193. clearCache() {
  194. this.existsCache.clear();
  195. this.packageJsonCache.clear();
  196. this.loadCache.clear();
  197. return this;
  198. }
  199. normalizeOptions(args) {
  200. const options = Object.assign({}, this.options);
  201. if (Object.prototype.toString.call(args[0]) === '[object Object]') {
  202. Object.assign(options, args[0]);
  203. } else {
  204. if (args[0]) {
  205. options.files = args[0];
  206. }
  207. if (args[1]) {
  208. options.cwd = args[1];
  209. }
  210. if (args[2]) {
  211. options.stopDir = args[2];
  212. }
  213. }
  214. options.cwd = _path.default.resolve(options.cwd);
  215. options.stopDir = options.stopDir ? _path.default.resolve(options.stopDir) : _path.default.parse(options.cwd).root;
  216. if (!options.files || options.files.length === 0) {
  217. throw new Error('[joycon] files must be an non-empty array!');
  218. }
  219. options.__normalized__ = true;
  220. return options;
  221. }
  222. }
  223. exports.default = JoyCon;
  224. module.exports = JoyCon;
  225. module.exports.default = JoyCon;