extractorUtils.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // Licensed to Cloudera, Inc. under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. Cloudera, Inc. licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. const fs = require('fs');
  17. const util = require('util');
  18. const LOG_NAME = 'extractorUtils.js';
  19. /**
  20. * Utility function to read a text file using UTF-8 encoding
  21. *
  22. * @param {string} path
  23. * @return {Promise} - A promise, fulfilled with the file contents or rejected
  24. */
  25. const readFile = path => new Promise((resolve, reject) => {
  26. fs.readFile(path, 'utf8', (err, contents) => {
  27. if (err) {
  28. console.log('%s: Could not read file \'%s\'', LOG_NAME, path);
  29. console.log(err);
  30. reject(err)
  31. } else {
  32. resolve(contents);
  33. }
  34. })
  35. });
  36. /**
  37. * Returns the parent folder of a file path
  38. *
  39. * @param {string} path
  40. * @return {string}
  41. */
  42. const getParentFolder = path => path.substring(0, path.lastIndexOf('/') + 1);
  43. /**
  44. * Checks arguments given on the command line, breaks the program if required ones are missing.
  45. *
  46. * @param {Object} program - See command lib
  47. */
  48. const checkArguments = program => {
  49. if (!program.folder) {
  50. console.log('\n No folder supplied!');
  51. program.help();
  52. }
  53. if (!program.ditamap) {
  54. console.log('\n No ditamap file supplied!');
  55. program.help();
  56. }
  57. if (!program.output) {
  58. console.log('\n No output path supplied!');
  59. program.help();
  60. }
  61. };
  62. /**
  63. * Helper method to check if a node has attributes that aren't empty
  64. *
  65. * @param node
  66. * @param {string|string[]} attributes
  67. * @return {boolean}
  68. */
  69. const hasAttributes = (node, attributes) => {
  70. if (typeof attributes === 'string') {
  71. attributes = [attributes];
  72. }
  73. return attributes.every(attribute => node.attr(attribute) && node.attr(attribute).value().trim())
  74. };
  75. /**
  76. * Helper method to remove all attributes of a noce
  77. *
  78. * @param node
  79. */
  80. const removeAllAttributes = node => {
  81. node.attrs().forEach(attr => {
  82. attr.remove();
  83. })
  84. };
  85. /**
  86. * Helper method to find a fragment with specified anchorId within a topic. If the anchor ID isn't found it will return
  87. * the closes possible parent.
  88. *
  89. * @param topic
  90. * @param anchorId
  91. * @return {[DocFragment]}
  92. */
  93. const findFragmentInTopic = (topic, anchorId) => {
  94. if (!anchorId) {
  95. return topic.fragment;
  96. }
  97. let splitIds = anchorId.split('/');
  98. let findDeep = (fragments, id) => {
  99. let foundFragment = undefined;
  100. fragments.some(fragment => {
  101. if (fragment.id === id) {
  102. foundFragment = fragment;
  103. return true;
  104. }
  105. foundFragment = findDeep(fragment.children, id);
  106. return foundFragment;
  107. });
  108. return foundFragment;
  109. };
  110. let fragmentsToSearch = [ topic.fragment ];
  111. let result = undefined;
  112. while (splitIds.length) {
  113. result = findDeep(fragmentsToSearch, splitIds.shift());
  114. if (!result) {
  115. break;
  116. }
  117. fragmentsToSearch = result.children;
  118. }
  119. if (!result) {
  120. console.log('%s: Could not find id \'%s\' in ref \'%s\'', LOG_NAME, anchorId, topic.ref);
  121. return topic.fragment;
  122. }
  123. return result;
  124. };
  125. /**
  126. * @typedef {Object} FragmentSearchResult
  127. * @property {boolean} partOfTree - Whether or not the found fragment is part of the main tree
  128. * @property {DocFragment} [fragment]
  129. */
  130. /**
  131. *
  132. * @param {DitamapParseResult[]} parseResults
  133. * @param {string} ref
  134. * @param {string} [anchorId]
  135. * @return {FragmentSearchResult}
  136. */
  137. const findFragment = (parseResults, ref, anchorId) => {
  138. let result = { partOfTree: true, fragment: undefined };
  139. parseResults.some(parseResult => {
  140. let topic = parseResult.topicIndex[ref];
  141. if (topic) {
  142. result.fragment = findFragmentInTopic(topic, anchorId);
  143. } else {
  144. result.partOfTree = false;
  145. }
  146. return result.fragment;
  147. });
  148. return result;
  149. };
  150. module.exports = {
  151. readFile: readFile,
  152. getParentFolder: getParentFolder,
  153. checkArguments: checkArguments,
  154. hasAttributes: hasAttributes,
  155. removeAllAttributes: removeAllAttributes,
  156. findFragment: findFragment
  157. };