generateParsers.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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 JISON_FOLDER = 'desktop/core/src/desktop/js/parse/jison/';
  34. const TARGET_FOLDER = 'desktop/core/src/desktop/js/parse/';
  35. const PARSERS = {
  36. globalSearchParser: {
  37. sources: ['globalSearchParser.jison'],
  38. target: 'globalSearchParser.jison',
  39. afterParse: (contents) => new Promise(resolve => {
  40. resolve(LICENSE +
  41. contents.replace('var globalSearchParser = ', 'import SqlParseSupport from \'parse/sqlParseSupport\';\n\nvar globalSearchParser = ') +
  42. '\nexport default globalSearchParser;\n');
  43. })
  44. },
  45. solrFormulaParser: {
  46. sources: ['solrFormulaParser.jison'],
  47. target: 'solrFormulaParser.jison',
  48. afterParse: (contents) => new Promise(resolve => {
  49. resolve(LICENSE + contents + 'export default solrFormulaParser;\n');
  50. })
  51. },
  52. solrQueryParser: {
  53. sources: ['solrQueryParser.jison'],
  54. target: 'solrQueryParser.jison',
  55. afterParse: (contents) => new Promise(resolve => {
  56. resolve(LICENSE + contents + 'export default solrQueryParser;\n');
  57. })
  58. },
  59. sqlAutocompleteParser: {
  60. sources: [
  61. 'autocomplete_header.jison', 'sql_main.jison', 'sql_valueExpression.jison', 'sql_error.jison', 'sql_alter.jison',
  62. 'sql_analyze.jison', 'sql_create.jison', 'sql_drop.jison', 'sql_grant.jison', 'sql_insert.jison', 'sql_load.jison',
  63. 'sql_set.jison', 'sql_show.jison', 'sql_update.jison', 'sql_use.jison', 'autocomplete_footer.jison'
  64. ],
  65. target: 'sqlAutocompleteParser.jison',
  66. lexer: 'sql.jisonlex',
  67. afterParse: (contents) => new Promise(resolve => {
  68. resolve(LICENSE +
  69. contents.replace('var sqlAutocompleteParser = ', 'import SqlParseSupport from \'parse/sqlParseSupport\';\n\nvar sqlAutocompleteParser = ') +
  70. '\nexport default sqlAutocompleteParser;\n');
  71. })
  72. },
  73. sqlStatementsParser: {
  74. sources: ['sqlStatementsParser.jison'],
  75. target: 'sqlStatementsParser.jison',
  76. afterParse: (contents) => new Promise(resolve => {
  77. resolve(LICENSE + contents + 'export default sqlStatementsParser;\n');
  78. })
  79. },
  80. sqlSyntaxParser: {
  81. sources: [
  82. 'syntax_header.jison', 'sql_main.jison', 'sql_valueExpression.jison', 'sql_alter.jison', 'sql_analyze.jison',
  83. 'sql_create.jison', 'sql_drop.jison', 'sql_grant.jison', 'sql_insert.jison', 'sql_load.jison', 'sql_set.jison',
  84. 'sql_show.jison', 'sql_update.jison', 'sql_use.jison', 'syntax_footer.jison'
  85. ],
  86. target: 'sqlSyntaxParser.jison',
  87. lexer: 'sql.jisonlex',
  88. afterParse: (contents) => new Promise(resolve => {
  89. resolve(LICENSE +
  90. contents.replace('var sqlSyntaxParser = ', 'import SqlParseSupport from \'parse/sqlParseSupport\';\n\nvar sqlSyntaxParser = ')
  91. .replace('loc: yyloc,', 'loc: lexer.yylloc, ruleId: stack.slice(stack.length - 2, stack.length).join(\'\'),') +
  92. '\nexport default sqlSyntaxParser;\n');
  93. })
  94. },
  95. };
  96. const readFile = (path) => new Promise((resolve, reject) => {
  97. fs.readFile(path, (err, buf) => {
  98. if (err) {
  99. reject();
  100. }
  101. resolve(buf.toString());
  102. })
  103. });
  104. const writeFile = (path, contents) => new Promise((resolve, reject) => {
  105. fs.writeFile(path, contents, function(err, data) {
  106. if (err) {
  107. reject();
  108. }
  109. resolve();
  110. });
  111. });
  112. const deleteFile = (path) => {
  113. fs.unlinkSync(path);
  114. };
  115. const execCmd = (cmd) => new Promise((resolve, reject) => {
  116. exec(cmd, function(err, stdout, stderr) {
  117. if (err) {
  118. reject();
  119. }
  120. resolve();
  121. });
  122. });
  123. const generateParser = parserName => new Promise((resolve, reject) => {
  124. let parserConfig = PARSERS[parserName];
  125. let concatPromise = new Promise((resolve, reject) => {
  126. if (parserConfig.sources.length > 1 && parserConfig.target) {
  127. console.log('Concatenating files...');
  128. let promises = parserConfig.sources.map(fileName => readFile(JISON_FOLDER + fileName));
  129. Promise.all(promises).then(contents => {
  130. writeFile(JISON_FOLDER + parserConfig.target, contents).then(() => {
  131. resolve(JISON_FOLDER + parserConfig.target)
  132. })
  133. }).catch(reject);
  134. } else if (parserConfig.sources.length === 1) {
  135. resolve(JISON_FOLDER + parserConfig.sources[0]);
  136. } else {
  137. reject('No jison source specified');
  138. }
  139. });
  140. concatPromise.then((targetPath) => {
  141. let jisonCommand = 'jison ' + targetPath;
  142. if (parserConfig.lexer) {
  143. jisonCommand += ' ' + JISON_FOLDER + parserConfig.lexer
  144. }
  145. jisonCommand += ' -m js';
  146. console.log('Generating parser...');
  147. execCmd(jisonCommand).then(() => {
  148. if (parserConfig.sources.length > 1) {
  149. deleteFile(targetPath); // Remove concatenated file
  150. }
  151. console.log('Adjusting JS...');
  152. let generatedJsFileName = parserConfig.target.replace('.jison', '.js');
  153. readFile(generatedJsFileName).then(contents => {
  154. parserConfig.afterParse(contents).then(finalContents => {
  155. writeFile(TARGET_FOLDER + generatedJsFileName, finalContents).then(() => {
  156. deleteFile(generatedJsFileName);
  157. console.log('Done!\n');
  158. resolve();
  159. }).catch(reject);
  160. }).catch(reject);
  161. }).catch(reject);
  162. }).catch(reject);
  163. }).catch(reject);
  164. });
  165. let parsersToGenerate = [];
  166. const invalid = [];
  167. let all = false;
  168. let appFound = false;
  169. process.argv.forEach(arg => {
  170. if (appFound) {
  171. if (arg === 'all') {
  172. all = true;
  173. } else if (PARSERS[arg]) {
  174. parsersToGenerate.push(arg);
  175. } else {
  176. invalid.push(arg);
  177. }
  178. } else if (arg.indexOf('generateParsers.js') !== -1) {
  179. appFound = true;
  180. }
  181. });
  182. if (all) {
  183. parsersToGenerate = Object.keys(PARSERS);
  184. }
  185. if (invalid.length) {
  186. console.log('No parser config found for: \'' + invalid.join('\', \'') + '\'');
  187. console.log('\nPossible options are:\n ' + ['all'].concat(Object.keys(PARSERS)).join('\n ') + '\n');
  188. return;
  189. }
  190. parserCount = parsersToGenerate.length;
  191. let idx = 0;
  192. const generateRecursive = () => {
  193. idx++;
  194. if (parsersToGenerate.length) {
  195. let parserName = parsersToGenerate.pop();
  196. if (parserCount > 1) {
  197. console.log('Generating \'' + parserName + '\' (' + idx + '/' + parserCount + ')...');
  198. } else {
  199. console.log('Generating \'' + parserName + '\'...');
  200. }
  201. generateParser(parserName).then(generateRecursive)
  202. }
  203. };
  204. generateRecursive();