reader.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * apidoc
  3. * https://apidocjs.com
  4. *
  5. * Authors:
  6. * Peter Rottmann <rottmann@inveris.de>
  7. * Nicolas CARPi @ Deltablot
  8. * Copyright (c) 2013 inveris OHG
  9. * Licensed under the MIT license.
  10. */
  11. const _ = require('lodash');
  12. const defaultConfig = {
  13. name: 'Acme project',
  14. version: '0.0.0',
  15. description: 'REST Api',
  16. };
  17. /**
  18. * Read information about the source code we are parsing from the config file
  19. */
  20. class Reader {
  21. constructor (app) {
  22. this.app = app;
  23. this.log = app.log;
  24. this.opt = app.options;
  25. this.fs = require('fs-extra');
  26. this.path = require('path');
  27. }
  28. // read the apidoc.json file, or apidoc.config.js or from the package.json
  29. read () {
  30. let config = {};
  31. // if the config file is provided, we use this and do no try to read other files
  32. if (this.opt.config) {
  33. this.log.debug('Config file provided, reading this.');
  34. config = require(this.path.resolve(this.opt.config));
  35. } else {
  36. config = this.search();
  37. }
  38. // replace header footer with file contents
  39. return Object.assign(config, this.getHeaderFooter(config));
  40. }
  41. /**
  42. * Look for config files in input folder
  43. */
  44. search () {
  45. this.log.debug('Now looking for apidoc config files');
  46. // possible sources of information
  47. const sources = [
  48. 'package.json',
  49. 'apidoc.json',
  50. 'apidoc.config.js',
  51. ];
  52. // create a new object because javascript will not assign value
  53. const config = Object.assign({}, defaultConfig);
  54. // loop the three possible source of information to try and find packageInfo
  55. sources.forEach(configFile => {
  56. this.log.debug(`Now looking for ${configFile}`);
  57. // first look in cwd dir
  58. Object.assign(config, this.findConfigFileInDir(configFile, process.cwd()));
  59. // scan each source dir to find a valid config file
  60. this.opt.src.forEach(dir => {
  61. Object.assign(config, this.findConfigFileInDir(configFile, dir));
  62. });
  63. });
  64. if (_.isEqual(config, defaultConfig)) {
  65. this.log.warn('No config files found.');
  66. }
  67. return config;
  68. }
  69. /**
  70. * Get json.header / json.footer title and markdown content (from file)
  71. *
  72. * @param {Object} config
  73. * @returns {Object}
  74. */
  75. getHeaderFooter (config) {
  76. const result = {};
  77. ['header', 'footer'].forEach(key => {
  78. if (config[key] && config[key].filename) {
  79. this.log.debug('Now looking for ' + key);
  80. // note that markdown files path is taken from first input value
  81. let filePath = this.path.join(config.input ? config.input[0] : './', config[key].filename);
  82. // try again to find it in current dir
  83. if (!this.fs.existsSync(filePath)) { filePath = this.path.join(process.cwd(), config[key].filename); }
  84. // try again to find it in input folders
  85. if (!this.fs.existsSync(filePath)) { filePath = this.findFileInSrc(config[key].filename); }
  86. // try again to find it in dir with the config file
  87. if (!this.fs.existsSync(filePath) && typeof this.opt.config === 'string') {
  88. filePath = this.path.join(this.path.dirname(this.opt.config), config[key].filename);
  89. }
  90. try {
  91. this.log.debug(`Reading ${key} file: ${filePath}`);
  92. const content = this.fs.readFileSync(filePath, 'utf8');
  93. result[key] = {
  94. title: config[key].title,
  95. content: this.app.markdownParser ? this.app.markdownParser.render(content) : content,
  96. };
  97. } catch (e) {
  98. throw new Error('Can not read: ' + filePath);
  99. }
  100. }
  101. });
  102. return result;
  103. }
  104. /**
  105. * Scan a directory for config files
  106. */
  107. findConfigFileInDir (filename, dir) {
  108. let foundConfig;
  109. const target = this.path.resolve(this.path.join(dir, filename));
  110. if (this.fs.existsSync(target)) {
  111. this.log.debug(`Found file: ${target}`);
  112. foundConfig = require(target);
  113. // if it has an apidoc key, read that
  114. if (foundConfig.apidoc) {
  115. this.log.verbose(`Using apidoc key of ${filename}`);
  116. // pull any missing config from root
  117. ['version', 'name', 'description'].forEach(key => {
  118. if (!foundConfig.apidoc[key] && foundConfig[key]) {
  119. this.log.verbose(`Using ${key} from root of ${filename}`);
  120. foundConfig.apidoc[key] = foundConfig[key];
  121. }
  122. });
  123. return foundConfig.apidoc;
  124. }
  125. // for package.json we don't want to read it if it has no apidoc key
  126. if (filename !== 'package.json') {
  127. return foundConfig;
  128. }
  129. }
  130. return {};
  131. }
  132. /**
  133. * Look for a file in each of the input folders
  134. */
  135. findFileInSrc (filename) {
  136. // scan each source dir to find a valid config file
  137. // note that any file found here will supersede a previously found file
  138. for (const dir of this.opt.src) {
  139. const target = this.path.join(dir, filename);
  140. if (this.fs.existsSync(target)) {
  141. this.log.debug('Found file: ' + target);
  142. return this.path.resolve(target);
  143. }
  144. }
  145. return '';
  146. }
  147. }
  148. module.exports = {
  149. Reader: Reader,
  150. defaultConfig: defaultConfig,
  151. };