Advertisement
Guest User

Untitled

a guest
Apr 18th, 2019
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.45 KB | None | 0 0
  1. // @flow
  2.  
  3. let { uniq, flatten } = require('lodash');
  4. let chalk = require('chalk');
  5. let dedent = require('dedent');
  6. let { isEqual, padStart, padEnd, trimEnd } = require('lodash');
  7. let fs = require('fs');
  8.  
  9. // NOTE CLASSIC
  10. const indent = indentLevel => (...args) => {
  11. const spaces = ``.repeat(indentLevel);
  12. const result = dedent(...args);
  13. return result.split('\n').map(x => `${spaces}${x}`).join('\n');
  14. };
  15.  
  16. /* ::
  17. type TFlowPoint = {
  18. line: number,
  19. column: number,
  20. offset: number,
  21. }
  22. type TFlowLocation = {
  23. source: string,
  24. type: 'JsonFile' | 'SourceFile' | 'LibFile',
  25. start: TFlowPoint,
  26. end: TFlowPoint,
  27. }
  28. type TFlowMessage = {
  29. context: string,
  30. descr: string,
  31. type: 'Blame' | 'Comment',
  32. loc: TFlowLocation,
  33. path: string,
  34. line: number,
  35. endline: number,
  36. start: number,
  37. end: number,
  38. }
  39.  
  40. type TFlowError = {
  41. kind: string,
  42. level: string,
  43. message: Array<TFlowMessage>,
  44. }
  45.  
  46. type TFlowReport = {
  47. flowVersion: number,
  48. errors: Array<TFlowError>,
  49. passed: boolean,
  50. }
  51. */
  52.  
  53. // NOTE CLASSIC
  54. const suck = stream => {
  55. return new Promise(function(yell, cry) {
  56. const content = [];
  57. process.stdin.on('readable', () => {
  58. const data: ?Buffer = (process.stdin.read(): any);
  59. if (data) content.push(data);
  60. else yell(Buffer.concat(content).toString());
  61. });
  62. });
  63. };
  64.  
  65. const suckText = async (...args) => (await suck(...args)).toString();
  66.  
  67. const does_not_contain_dot_directory = message =>
  68. message.path.split('/').every(name => !name.startsWith('.'));
  69. const does_not_contain_node_modules = message =>
  70. message.path.split('/').every(name => name !== 'node_modules');
  71.  
  72. // NOTE CLASSIC
  73. const not = fn => (...args) => !fn(...args);
  74. // NOTE CLASSIC
  75. const divide = (xs, pred) => [xs.filter(pred), xs.filter(not(pred))];
  76.  
  77. const workdir = '/Users/michieldral/Projects/uButler Portal/';
  78. // NOTE CLASSIC
  79. const without_prefix = (string: string, prefix: string) => {
  80. if (!string.startsWith(prefix)) return string;
  81. else return string.slice(prefix.length);
  82. };
  83. // const pretty_print = (obj) => JSON.stringify(obj, null, 2)
  84.  
  85. // const FLOW_START = { line: 0, column: 0, offset: 0 };
  86. // const FLOW_END = { line: Infinity, column: Infinity, offset: Infinity };
  87. // const string_range = (string, start: TFlowPoint, end: TFlowPoint) => {
  88. // return string.slice(start.column, end.column);
  89. // }
  90. const decorate_string_range = (range: TFlowLocation, string, mapFn) => {
  91. return [
  92. string.slice(0, range.start.column - 1),
  93. mapFn(string.slice(range.start.column - 1, range.end.column)),
  94. string.slice(range.end.column, Infinity),
  95. ].join('');
  96. };
  97.  
  98. const count_regex = (str, regex) => {
  99. let m = str.match(regex);
  100. return m ? m.length : 0;
  101. };
  102.  
  103. const count_control_char = str => {
  104. return count_regex(str, /[\x00-\x1F\x7F-\x9F]/g) * 5;
  105. };
  106.  
  107. const mark_characters = str => {
  108. return str.replace(
  109. /([ ]*)(.*[^ ])([ ]*)/,
  110. '$1' + chalk.bgRed.black('$2') + '$3',
  111. );
  112. };
  113.  
  114. const prefix_lines = (str, prefix) => {
  115. return str.split('\n').map(line => `${prefix}${line}`).join('\n');
  116. };
  117.  
  118. const print_code = async message => {
  119. if (!message.loc) throw new Error();
  120. const loc = message.loc;
  121.  
  122. const all_lines = fs.readFileSync(loc.source).toString().split('\n');
  123.  
  124. let indented;
  125. if (loc.start.line === loc.end.line) {
  126. const before = all_lines.slice(loc.start.line - 3, loc.start.line - 1);
  127. const the_line = all_lines[loc.start.line - 1];
  128. const after = all_lines.slice(loc.end.line, loc.end.line + 2);
  129.  
  130. const the_line_before = the_line.slice(0, loc.start.column - 1);
  131. const the_line_marked = the_line.slice(
  132. loc.start.column - 1,
  133. loc.end.column,
  134. );
  135. const the_line_after = the_line.slice(loc.end.column);
  136.  
  137. indented =
  138. before.join('\n') +
  139. '\n' +
  140. the_line_before +
  141. mark_characters(the_line_marked) +
  142. the_line_after +
  143. '\n' +
  144. after.join('\n');
  145. } else {
  146. const before = all_lines.slice(loc.start.line - 3, loc.start.line - 1);
  147. const partial_first = all_lines[loc.start.line - 1];
  148. const middle = all_lines.slice(loc.start.line, loc.end.line - 1);
  149. const partial_last = all_lines[loc.end.line - 1];
  150. const after = all_lines.slice(loc.end.line, loc.end.line + 2);
  151.  
  152. const middle_with_marks = middle.map(line => mark_characters(line));
  153.  
  154. const partial_first_unmarked = partial_first.slice(0, loc.start.column - 1);
  155. const partial_first_marked = partial_first.slice(loc.start.column - 1);
  156.  
  157. const partial_last_marked = partial_last.slice(0, loc.end.column);
  158. const partial_last_unmarked = partial_last.slice(loc.end.column);
  159.  
  160. indented =
  161. before.join('\n') +
  162. '\n' +
  163. partial_first_unmarked +
  164. mark_characters(partial_first_marked) +
  165. '\n' +
  166. middle_with_marks.join('\n') +
  167. '\n' +
  168. mark_characters(partial_last_marked) +
  169. partial_last_unmarked +
  170. '\n' +
  171. after.join('\n');
  172. }
  173.  
  174. let dedented = dedent(
  175. indented.split('\n').map(x => ` ${x}`).join('\n'),
  176. ).split('\n');
  177.  
  178. let box_width = Math.max(
  179. dedented
  180. .slice()
  181. // Remove control characters (colors)
  182. .map(x => x.replace(/[\x00-\x1F\x7F-\x9F]/g, ''))
  183. .sort((a, b) => b.length - a.length)[0].length,
  184. 50,
  185. );
  186.  
  187. return dedented
  188. .map((line, i) => ` ${padEnd(loc.start.line - 2 + i + ':', 6)}${line}`)
  189. .map(line => padEnd(line, box_width + count_control_char(line) + 8))
  190. .map(line => chalk.bgWhite.black(line))
  191. .join('\n');
  192. };
  193.  
  194. const main = async ({ show_missing_annotations = false }) => {
  195. const json = await suckText(process.stdin);
  196. const result = JSON.parse(json.toString());
  197.  
  198. const allKinds = uniq(result.errors.map(x => x.kind));
  199. const allLevels = uniq(result.errors.map(x => x.level));
  200.  
  201. const allMessages = flatten(result.errors.map(x => x.message));
  202. const allTypes = uniq(allMessages.map(x => x.type));
  203. const allLocTypes = uniq(allMessages.map(x => x.loc && x.loc.type));
  204.  
  205. console.log('Object.keys(result):', Object.keys(result));
  206. console.log('allKinds:', allKinds);
  207. console.log('allLevels:', allLevels);
  208. console.log('allLocTypes:', allLocTypes);
  209. console.log('allTypes:', allTypes);
  210.  
  211. const errors = result.errors
  212. .filter(err => err.message.every(does_not_contain_dot_directory))
  213. .filter(err => err.message.every(does_not_contain_node_modules));
  214.  
  215. const [parse_errors, infer_errors] = divide(
  216. errors,
  217. err => err.kind === 'parse',
  218. );
  219.  
  220. const parse_messages = parse_errors.map(
  221. error => dedent`
  222. ${chalk.red(`===`)} Parse error in file
  223. ${without_prefix(error.message[0].path, workdir)}
  224. `,
  225. );
  226. console.log('\n\n', parse_messages.join('\n'));
  227.  
  228. const infer_messages = await Promise.all(
  229. infer_errors.map(async (error: TFlowError) => {
  230. const structure = error.message.map(m => m.type);
  231.  
  232. if (isEqual(structure, ['Blame', 'Comment'])) {
  233. const [blame, comment] = error.message;
  234.  
  235. if (!blame.loc) throw new Error();
  236. if (!show_missing_annotations && comment.descr === 'Missing annotation')
  237. return '';
  238.  
  239. const loc = blame.loc;
  240.  
  241. let code = await print_code(blame);
  242.  
  243. return indent(0)`
  244. ${chalk.blue(`[File]`)} In ${chalk.blue(
  245. without_prefix(blame.path, workdir),
  246. )}
  247. ${prefix_lines(code, chalk.blue(`[Code] `))}
  248. ${chalk.blue(`[Line]`)}
  249. ${chalk.blue(`[Line]`)} > ${chalk.yellow(blame.descr)}
  250. ${chalk.blue(`[Line]`)} ${comment.descr}
  251. `;
  252. } else if (isEqual(structure, ['Blame', 'Comment', 'Blame'])) {
  253. const [blame1, comment, blame2] = error.message;
  254.  
  255. if (!blame1.loc || !blame2.loc) throw new Error();
  256. if (!show_missing_annotations && comment.descr === 'Missing annotation')
  257. return '';
  258.  
  259. let code1 = await print_code(blame1);
  260. let code2 = await print_code(blame2);
  261.  
  262. return indent(0)`
  263. ${chalk.blue(`[File]`)} In ${chalk.blue(
  264. without_prefix(blame1.path, workdir),
  265. )}
  266. ${prefix_lines(code1, chalk.blue(`[Code] `))}
  267. ${chalk.blue(`[Line]`)}
  268. ${chalk.blue(`[Line]`)} > ${chalk.yellow(blame1.descr)}
  269. ${chalk.blue(`[Line]`)} ${comment.descr}
  270. ${chalk.blue(`[Line]`)} > ${chalk.yellow(blame2.descr)}
  271. ${chalk.blue(`[Line]`)}
  272. ${chalk.blue(`[File]`)} In ${chalk.blue(
  273. without_prefix(blame2.path, workdir),
  274. )}
  275. ${prefix_lines(code2, chalk.blue(`[Code] `))}
  276. `;
  277. } else {
  278. return chalk.green(structure.join(', '));
  279. }
  280. }),
  281. );
  282.  
  283. console.log('\n');
  284. console.log(infer_messages.filter(Boolean).join('\n\n\n'));
  285. };
  286.  
  287. main({}).catch(err => {
  288. console.log('err:', err);
  289. });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement