parserDefinitions.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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. /* eslint-disable no-restricted-syntax */
  17. import { fileExists, listDir, readFile } from './utils.js';
  18. const LICENSE = `// Licensed to Cloudera, Inc. under one
  19. // or more contributor license agreements. See the NOTICE file
  20. // distributed with this work for additional information
  21. // regarding copyright ownership. Cloudera, Inc. licenses this file
  22. // to you under the Apache License, Version 2.0 (the
  23. // "License"); you may not use this file except in compliance
  24. // with the License. You may obtain a copy of the License at
  25. //
  26. // http://www.apache.org/licenses/LICENSE-2.0
  27. //
  28. // Unless required by applicable law or agreed to in writing, software
  29. // distributed under the License is distributed on an "AS IS" BASIS,
  30. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  31. // See the License for the specific language governing permissions and
  32. // limitations under the License.
  33. `;
  34. const SQL_STATEMENTS_PARSER_JSDOC = `/**
  35. * @param {string} input
  36. *
  37. * @return {SqlStatementsParserResult}
  38. */
  39. `;
  40. const AUTOCOMPLETE_PARSER_JSDOC = `/**
  41. * @param {string} input
  42. *
  43. * @return {AutocompleteParseResult}
  44. */
  45. `;
  46. const PARSER_FOLDER = '../../desktop/core/src/desktop/js/parse';
  47. const SQL_FOLDER = '../../desktop/core/src/desktop/js/parse/sql';
  48. /*
  49. The FIXED_PARSER_DEFINITIONS are for parsers other than the ones used for SQL autocomplete and syntax
  50. which are identified automatically under SQL_FOLDER
  51. The "afterParse" function can be used to modify the generated parser code, for instance, add the license header,
  52. add specific imports, and make sure it is ES modules compatible etc.
  53. */
  54. const FIXED_PARSER_DEFINITIONS = {
  55. globalSearchParser: {
  56. sources: [`${PARSER_FOLDER}/jison/globalSearchParser.jison`],
  57. targetJison: 'globalSearchParser.jison',
  58. outputFolder: PARSER_FOLDER,
  59. parserName: 'globalSearchParser',
  60. afterParse: async contents =>
  61. `${LICENSE}${contents.replace(
  62. 'var globalSearchParser = ',
  63. "import SqlParseSupport from 'parse/sqlParseSupport';\n\nvar globalSearchParser = "
  64. )}\nexport default globalSearchParser;\n`
  65. },
  66. solrFormulaParser: {
  67. sources: [`${PARSER_FOLDER}/jison/solrFormulaParser.jison`],
  68. targetJison: 'solrFormulaParser.jison',
  69. outputFolder: PARSER_FOLDER,
  70. parserName: 'solrFormulaParser',
  71. afterParse: async contents => `${LICENSE}${contents}\nexport default solrFormulaParser;\n`
  72. },
  73. solrQueryParser: {
  74. sources: [`${PARSER_FOLDER}/jison/solrQueryParser.jison`],
  75. targetJison: 'solrQueryParser.jison',
  76. outputFolder: PARSER_FOLDER,
  77. parserName: 'solrQueryParser',
  78. afterParse: async contents => `${LICENSE}${contents}\nexport default solrQueryParser;\n`
  79. },
  80. sqlStatementsParser: {
  81. sources: [`${PARSER_FOLDER}/jison/sqlStatementsParser.jison`],
  82. targetJison: 'sqlStatementsParser.jison',
  83. outputFolder: PARSER_FOLDER,
  84. parserName: 'sqlStatementsParser',
  85. afterParse: async contents =>
  86. `${LICENSE}${contents.replace(
  87. 'parse: function parse',
  88. SQL_STATEMENTS_PARSER_JSDOC + 'parse: function parse'
  89. )}\nexport default sqlStatementsParser;\n`
  90. },
  91. hplsqlStatementsParser: {
  92. sources: [`${PARSER_FOLDER}/jison/hplsqlStatementsParser.jison`],
  93. targetJison: 'hplsqlStatementsParser.jison',
  94. outputFolder: PARSER_FOLDER,
  95. parserName: 'hplsqlStatementsParser',
  96. afterParse: async contents =>
  97. `${LICENSE}${contents.replace(
  98. 'parse: function parse',
  99. SQL_STATEMENTS_PARSER_JSDOC + 'parse: function parse'
  100. )}\nexport default hplsqlStatementsParser;\n`
  101. }
  102. };
  103. /**
  104. * Searches through the SQL_FOLDER and if a jison/structure.json file exists it considers it a parser
  105. */
  106. const findParserSources = async () => {
  107. const folders = await listDir(SQL_FOLDER);
  108. const structureFiles = [];
  109. for (const folder of folders) {
  110. const outputFolder = `${SQL_FOLDER}/${folder}`;
  111. const jisonFolder = `${outputFolder}/jison`;
  112. const structureFile = `${jisonFolder}/structure.json`;
  113. if (fileExists(structureFile)) {
  114. structureFiles.push({ dialect: folder, outputFolder, jisonFolder, structureFile });
  115. }
  116. }
  117. return structureFiles;
  118. };
  119. /**
  120. * Identifies all the SQL parsers based on subfolders in SQL_FOLDER and adds them to parserDefinitions
  121. */
  122. export const identifySqlParsers = async () => {
  123. const parserSources = await findParserSources();
  124. const foundDefinitions = {};
  125. for (const parserSource of parserSources) {
  126. const structure = JSON.parse(await readFile(parserSource.structureFile));
  127. if (structure.autocomplete) {
  128. foundDefinitions[`${parserSource.dialect}AutocompleteParser`] = createParserDefinition(
  129. structure.autocomplete,
  130. parserSource,
  131. true,
  132. structure
  133. );
  134. }
  135. if (structure.syntax) {
  136. foundDefinitions[`${parserSource.dialect}SyntaxParser`] = createParserDefinition(
  137. structure.syntax,
  138. parserSource,
  139. false,
  140. structure
  141. );
  142. }
  143. }
  144. return { ...FIXED_PARSER_DEFINITIONS, ...foundDefinitions };
  145. };
  146. const createParserDefinition = (
  147. sources,
  148. { dialect, outputFolder, jisonFolder },
  149. autocomplete,
  150. { lexer, imports }
  151. ) => {
  152. const parserName = `${dialect}${autocomplete ? 'AutocompleteParser' : 'SyntaxParser'}`;
  153. const absoluteSources = sources.map(source => `${jisonFolder}/${source}`);
  154. for (const source of absoluteSources) {
  155. if (!fileExists(source)) {
  156. throw new Error(
  157. `Could not find the file '${source}' as defined in structure.json for ${dialect}`
  158. );
  159. }
  160. }
  161. return {
  162. sources: sources.map(source => `${jisonFolder}/${source}`),
  163. lexer: `${jisonFolder}/${lexer}`,
  164. targetJison: `${outputFolder}/${parserName}.jison`,
  165. sqlParser: autocomplete ? 'AUTOCOMPLETE' : 'SYNTAX',
  166. parserName,
  167. outputFolder,
  168. afterParse: async contents =>
  169. `${LICENSE}${contents
  170. // Add default import of sqlParseSupport or imports specified in the structure file
  171. .replace(
  172. `var ${parserName} = `,
  173. imports
  174. ? `${imports.join(';\n')};\n\n$var ${parserName} = `
  175. : `import SqlParseSupport from 'parse/sql/${dialect}/sqlParseSupport';\n\nvar ${parserName} = `
  176. )
  177. // Add jsdoc to the parse function
  178. .replace('parse: function parse', AUTOCOMPLETE_PARSER_JSDOC + 'parse: function parse')
  179. // Fix a bug in jison (https://github.com/zaach/jison/pull/356)
  180. .replace(
  181. 'loc: yyloc,',
  182. "loc: lexer.yylloc, ruleId: stack.slice(stack.length - 2, stack.length).join(''),"
  183. )}\nexport default ${parserName};\n`
  184. };
  185. };
  186. /* eslint-enable no-restricted-syntax */