generateParsers.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. let fs = require('fs');
  17. let exec = require('child_process').exec;
  18. const LICENSE = '// Licensed to Cloudera, Inc. under one\n' +
  19. '// or more contributor license agreements. See the NOTICE file\n' +
  20. '// distributed with this work for additional information\n' +
  21. '// regarding copyright ownership. Cloudera, Inc. licenses this file\n' +
  22. '// to you under the Apache License, Version 2.0 (the\n' +
  23. '// "License"); you may not use this file except in compliance\n' +
  24. '// with the License. You may obtain a copy of the License at\n' +
  25. '//\n' +
  26. '// http://www.apache.org/licenses/LICENSE-2.0\n' +
  27. '//\n' +
  28. '// Unless required by applicable law or agreed to in writing, software\n' +
  29. '// distributed under the License is distributed on an "AS IS" BASIS,\n' +
  30. '// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' +
  31. '// See the License for the specific language governing permissions and\n' +
  32. '// limitations under the License.\n';
  33. const SQL_STATEMENTS_PARSER_JSDOC = '/**\n' +
  34. ' * @param {string} input\n' +
  35. ' *\n' +
  36. ' * @return {SqlStatementsParserResult}\n' +
  37. ' */\n';
  38. const JISON_FOLDER = 'desktop/core/src/desktop/js/parse/jison/';
  39. const TARGET_FOLDER = 'desktop/core/src/desktop/js/parse/';
  40. const PARSERS = {
  41. globalSearchParser: {
  42. sources: ['globalSearchParser.jison'],
  43. target: 'globalSearchParser.jison',
  44. afterParse: (contents) => new Promise(resolve => {
  45. resolve(LICENSE +
  46. contents.replace('var globalSearchParser = ', 'import SqlParseSupport from \'parse/sqlParseSupport\';\n\nvar globalSearchParser = ') +
  47. '\nexport default globalSearchParser;\n');
  48. })
  49. },
  50. solrFormulaParser: {
  51. sources: ['solrFormulaParser.jison'],
  52. target: 'solrFormulaParser.jison',
  53. afterParse: (contents) => new Promise(resolve => {
  54. resolve(LICENSE + contents + 'export default solrFormulaParser;\n');
  55. })
  56. },
  57. solrQueryParser: {
  58. sources: ['solrQueryParser.jison'],
  59. target: 'solrQueryParser.jison',
  60. afterParse: (contents) => new Promise(resolve => {
  61. resolve(LICENSE + contents + 'export default solrQueryParser;\n');
  62. })
  63. },
  64. sqlAutocompleteParser: {
  65. sources: [
  66. 'autocomplete_header.jison', 'sql_main.jison', 'sql_valueExpression.jison', 'sql_error.jison', 'sql_alter.jison',
  67. 'sql_analyze.jison', 'sql_create.jison', 'sql_drop.jison', 'sql_grant.jison', 'sql_insert.jison', 'sql_load.jison',
  68. 'sql_set.jison', 'sql_show.jison', 'sql_update.jison', 'sql_use.jison', 'autocomplete_footer.jison'
  69. ],
  70. target: 'sqlAutocompleteParser.jison',
  71. lexer: 'sql.jisonlex',
  72. afterParse: (contents) => new Promise(resolve => {
  73. resolve(LICENSE +
  74. contents.replace('var sqlAutocompleteParser = ', 'import SqlParseSupport from \'parse/sqlParseSupport\';\n\nvar sqlAutocompleteParser = ') +
  75. '\nexport default sqlAutocompleteParser;\n');
  76. })
  77. },
  78. sqlStatementsParser: {
  79. sources: ['sqlStatementsParser.jison'],
  80. target: 'sqlStatementsParser.jison',
  81. afterParse: (contents) => new Promise(resolve => {
  82. resolve(LICENSE + contents.replace('parse: function parse', SQL_STATEMENTS_PARSER_JSDOC + 'parse: function parse') + 'export default sqlStatementsParser;\n');
  83. })
  84. },
  85. sqlSyntaxParser: {
  86. sources: [
  87. 'syntax_header.jison', 'sql_main.jison', 'sql_valueExpression.jison', 'sql_alter.jison', 'sql_analyze.jison',
  88. 'sql_create.jison', 'sql_drop.jison', 'sql_grant.jison', 'sql_insert.jison', 'sql_load.jison', 'sql_set.jison',
  89. 'sql_show.jison', 'sql_update.jison', 'sql_use.jison', 'syntax_footer.jison'
  90. ],
  91. target: 'sqlSyntaxParser.jison',
  92. lexer: 'sql.jisonlex',
  93. afterParse: (contents) => new Promise(resolve => {
  94. resolve(LICENSE +
  95. contents.replace('var sqlSyntaxParser = ', 'import SqlParseSupport from \'parse/sqlParseSupport\';\n\nvar sqlSyntaxParser = ')
  96. .replace('loc: yyloc,', 'loc: lexer.yylloc, ruleId: stack.slice(stack.length - 2, stack.length).join(\'\'),') +
  97. '\nexport default sqlSyntaxParser;\n');
  98. })
  99. },
  100. };
  101. const readFile = (path) => new Promise((resolve, reject) => {
  102. fs.readFile(path, (err, buf) => {
  103. if (err) {
  104. reject();
  105. }
  106. resolve(buf.toString());
  107. })
  108. });
  109. const writeFile = (path, contents) => new Promise((resolve, reject) => {
  110. fs.writeFile(path, contents, function(err, data) {
  111. if (err) {
  112. reject();
  113. }
  114. resolve();
  115. });
  116. });
  117. const deleteFile = (path) => {
  118. fs.unlinkSync(path);
  119. };
  120. const execCmd = (cmd) => new Promise((resolve, reject) => {
  121. exec(cmd, function(err, stdout, stderr) {
  122. if (err) {
  123. reject(stderr);
  124. }
  125. resolve();
  126. });
  127. });
  128. const generateParser = parserName => new Promise((resolve, reject) => {
  129. let parserConfig = PARSERS[parserName];
  130. let concatPromise = new Promise((resolve, reject) => {
  131. if (parserConfig.sources.length > 1 && parserConfig.target) {
  132. console.log('Concatenating files...');
  133. let promises = parserConfig.sources.map(fileName => readFile(JISON_FOLDER + fileName));
  134. Promise.all(promises).then(contents => {
  135. writeFile(JISON_FOLDER + parserConfig.target, contents).then(() => {
  136. resolve(JISON_FOLDER + parserConfig.target)
  137. })
  138. }).catch(reject);
  139. } else if (parserConfig.sources.length === 1) {
  140. resolve(JISON_FOLDER + parserConfig.sources[0]);
  141. } else {
  142. reject('No jison source specified');
  143. }
  144. });
  145. concatPromise.then((targetPath) => {
  146. let jisonCommand = 'jison ' + targetPath;
  147. if (parserConfig.lexer) {
  148. jisonCommand += ' ' + JISON_FOLDER + parserConfig.lexer
  149. }
  150. jisonCommand += ' -m js';
  151. console.log('Generating parser...');
  152. execCmd(jisonCommand).then(() => {
  153. if (parserConfig.sources.length > 1) {
  154. deleteFile(targetPath); // Remove concatenated file
  155. }
  156. console.log('Adjusting JS...');
  157. let generatedJsFileName = parserConfig.target.replace('.jison', '.js');
  158. readFile(generatedJsFileName).then(contents => {
  159. parserConfig.afterParse(contents).then(finalContents => {
  160. writeFile(TARGET_FOLDER + generatedJsFileName, finalContents).then(() => {
  161. deleteFile(generatedJsFileName);
  162. console.log('Done!\n');
  163. resolve();
  164. }).catch(reject);
  165. }).catch(reject);
  166. }).catch(reject);
  167. }).catch(reject);
  168. }).catch(reject);
  169. });
  170. let parsersToGenerate = [];
  171. const invalid = [];
  172. let all = false;
  173. let appFound = false;
  174. process.argv.forEach(arg => {
  175. if (appFound) {
  176. if (arg === 'all') {
  177. all = true;
  178. } else if (PARSERS[arg]) {
  179. parsersToGenerate.push(arg);
  180. } else {
  181. invalid.push(arg);
  182. }
  183. } else if (arg.indexOf('generateParsers.js') !== -1) {
  184. appFound = true;
  185. }
  186. });
  187. if (all) {
  188. parsersToGenerate = Object.keys(PARSERS);
  189. }
  190. if (invalid.length) {
  191. console.log('No parser config found for: \'' + invalid.join('\', \'') + '\'');
  192. console.log('\nPossible options are:\n ' + ['all'].concat(Object.keys(PARSERS)).join('\n ') + '\n');
  193. return;
  194. }
  195. parserCount = parsersToGenerate.length;
  196. let idx = 0;
  197. const generateRecursive = () => {
  198. idx++;
  199. if (parsersToGenerate.length) {
  200. let parserName = parsersToGenerate.pop();
  201. if (parserCount > 1) {
  202. console.log('Generating \'' + parserName + '\' (' + idx + '/' + parserCount + ')...');
  203. } else {
  204. console.log('Generating \'' + parserName + '\'...');
  205. }
  206. generateParser(parserName).then(generateRecursive).catch(error => {
  207. console.log(error);
  208. console.log('FAIL!');
  209. })
  210. }
  211. };
  212. generateRecursive();