UI for Zipcoin Blue

parse.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. "use strict";
  2. /*
  3. * @license
  4. * Copyright 2016 Palantir Technologies, Inc.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. Object.defineProperty(exports, "__esModule", { value: true });
  19. var semver = require("semver");
  20. var ts = require("typescript");
  21. var util_1 = require("util");
  22. var utils_1 = require("../utils");
  23. var lines_1 = require("./lines");
  24. var lintError_1 = require("./lintError");
  25. var scanner;
  26. function getTypescriptVersionRequirement(text) {
  27. var lines = text.split(/\r?\n/);
  28. var firstLine = lines_1.parseLine(lines[0]);
  29. if (firstLine instanceof lines_1.MessageSubstitutionLine && firstLine.key === "typescript") {
  30. return firstLine.message;
  31. }
  32. return undefined;
  33. }
  34. exports.getTypescriptVersionRequirement = getTypescriptVersionRequirement;
  35. function getNormalizedTypescriptVersion() {
  36. var tsVersion = new semver.SemVer(ts.version);
  37. // remove prerelease suffix when matching to allow testing with nightly builds
  38. return tsVersion.major + "." + tsVersion.minor + "." + tsVersion.patch;
  39. }
  40. exports.getNormalizedTypescriptVersion = getNormalizedTypescriptVersion;
  41. function preprocessDirectives(text) {
  42. if (!/^#(?:if|else|endif)\b/m.test(text)) {
  43. return text; // If there are no directives, just return the input unchanged
  44. }
  45. var tsVersion = getNormalizedTypescriptVersion();
  46. var lines = text.split(/\n/);
  47. var result = [];
  48. var collecting = true;
  49. var state = 0 /* Initial */;
  50. for (var _i = 0, lines_2 = lines; _i < lines_2.length; _i++) {
  51. var line = lines_2[_i];
  52. if (line.startsWith("#if typescript")) {
  53. if (state !== 0 /* Initial */) {
  54. throw lintError_1.lintSyntaxError("#if directives cannot be nested");
  55. }
  56. state = 1 /* If */;
  57. collecting = semver.satisfies(tsVersion, line.slice("#if typescript".length).trim());
  58. }
  59. else if (/^#else\s*$/.test(line)) {
  60. if (state !== 1 /* If */) {
  61. throw lintError_1.lintSyntaxError("unexpected #else");
  62. }
  63. state = 2 /* Else */;
  64. collecting = !collecting;
  65. }
  66. else if (/^#endif\s*$/.test(line)) {
  67. if (state === 0 /* Initial */) {
  68. throw lintError_1.lintSyntaxError("unexpected #endif");
  69. }
  70. state = 0 /* Initial */;
  71. collecting = true;
  72. }
  73. else if (collecting) {
  74. result.push(line);
  75. }
  76. }
  77. if (state !== 0 /* Initial */) {
  78. throw lintError_1.lintSyntaxError("expected #endif");
  79. }
  80. return result.join("\n");
  81. }
  82. exports.preprocessDirectives = preprocessDirectives;
  83. /**
  84. * Takes the full text of a .lint file and returns the contents of the file
  85. * with all error markup removed
  86. */
  87. function removeErrorMarkup(text) {
  88. var textWithMarkup = text.split("\n");
  89. var lines = textWithMarkup.map(lines_1.parseLine);
  90. var codeText = lines.filter(function (line) { return (line instanceof lines_1.CodeLine); }).map(function (line) { return line.contents; });
  91. return codeText.join("\n");
  92. }
  93. exports.removeErrorMarkup = removeErrorMarkup;
  94. /* tslint:disable:object-literal-sort-keys */
  95. /**
  96. * Takes the full text of a .lint file and returns an array of LintErrors
  97. * corresponding to the error markup in the file.
  98. */
  99. function parseErrorsFromMarkup(text) {
  100. var textWithMarkup = text.split("\n");
  101. var lines = textWithMarkup.map(lines_1.parseLine);
  102. if (lines.length > 0 && !(lines[0] instanceof lines_1.CodeLine)) {
  103. throw lintError_1.lintSyntaxError("text cannot start with an error mark line.");
  104. }
  105. var messageSubstitutionLines = lines.filter(function (l) { return l instanceof lines_1.MessageSubstitutionLine; });
  106. var messageSubstitutions = new Map();
  107. for (var _i = 0, messageSubstitutionLines_1 = messageSubstitutionLines; _i < messageSubstitutionLines_1.length; _i++) {
  108. var _a = messageSubstitutionLines_1[_i], key = _a.key, message = _a.message;
  109. messageSubstitutions.set(key, formatMessage(messageSubstitutions, message));
  110. }
  111. // errorLineForCodeLine[5] contains all the ErrorLine objects associated with the 5th line of code, for example
  112. var errorLinesForCodeLines = createCodeLineNoToErrorsMap(lines);
  113. var lintErrors = [];
  114. function addError(errorLine, errorStartPos, lineNo) {
  115. lintErrors.push({
  116. startPos: errorStartPos,
  117. endPos: { line: lineNo, col: errorLine.endCol },
  118. message: substituteMessage(messageSubstitutions, errorLine.message),
  119. });
  120. }
  121. // for each line of code...
  122. errorLinesForCodeLines.forEach(function (errorLinesForLineOfCode, lineNo) {
  123. // for each error marking on that line...
  124. while (errorLinesForLineOfCode.length > 0) {
  125. var errorLine = errorLinesForLineOfCode.shift();
  126. var errorStartPos = { line: lineNo, col: errorLine.startCol };
  127. // if the error starts and ends on this line, add it now to list of errors
  128. if (errorLine instanceof lines_1.EndErrorLine) {
  129. addError(errorLine, errorStartPos, lineNo);
  130. // if the error is the start of a multiline error
  131. }
  132. else if (errorLine instanceof lines_1.MultilineErrorLine) {
  133. // iterate through the MultilineErrorLines until we get to an EndErrorLine
  134. for (var nextLineNo = lineNo + 1;; ++nextLineNo) {
  135. if (!isValidErrorMarkupContinuation(errorLinesForCodeLines, nextLineNo)) {
  136. throw lintError_1.lintSyntaxError("Error mark starting at " + errorStartPos.line + ":" + errorStartPos.col + " does not end correctly.");
  137. }
  138. else {
  139. var nextErrorLine = errorLinesForCodeLines[nextLineNo].shift();
  140. // if end of multiline error, add it it list of errors
  141. if (nextErrorLine instanceof lines_1.EndErrorLine) {
  142. addError(nextErrorLine, errorStartPos, nextLineNo);
  143. break;
  144. }
  145. }
  146. }
  147. }
  148. }
  149. });
  150. lintErrors.sort(lintError_1.errorComparator);
  151. return lintErrors;
  152. }
  153. exports.parseErrorsFromMarkup = parseErrorsFromMarkup;
  154. /**
  155. * Process `message` as follows:
  156. * - search `substitutions` for an exact match and return the substitution
  157. * - try to format the message when it looks like: name % ('substitution1' [, "substitution2" [, ...]])
  158. * - or return it unchanged
  159. */
  160. function substituteMessage(templates, message) {
  161. var substitution = templates.get(message);
  162. if (substitution !== undefined) {
  163. return substitution;
  164. }
  165. return formatMessage(templates, message);
  166. }
  167. /**
  168. * Tries to format the message when it has the correct format or returns it unchanged: name % ('substitution1' [, "substitution2" [, ...]])
  169. * Where `name` is the name of a message substitution that is used as template.
  170. * If `name` is not found in `templates`, `message` is returned unchanged.
  171. */
  172. function formatMessage(templates, message) {
  173. var formatMatch = /^([-\w]+) % \((.+)\)$/.exec(message);
  174. if (formatMatch !== null) {
  175. var template = templates.get(formatMatch[1]);
  176. if (template !== undefined) {
  177. var formatArgs = parseFormatArguments(formatMatch[2]);
  178. if (formatArgs !== undefined) {
  179. message = util_1.format.apply(void 0, [template].concat(formatArgs));
  180. }
  181. }
  182. }
  183. return message;
  184. }
  185. /**
  186. * Parse a list of comma separated string literals.
  187. * This function bails out if it sees something unexpected.
  188. * Whitespace between tokens is ignored.
  189. * Trailing comma is allowed.
  190. */
  191. function parseFormatArguments(text) {
  192. if (scanner === undefined) {
  193. // once the scanner is created, it is cached for subsequent calls
  194. scanner = ts.createScanner(ts.ScriptTarget.Latest, false);
  195. }
  196. scanner.setText(text);
  197. var result = [];
  198. var expectValue = true;
  199. for (var token = scanner.scan(); token !== ts.SyntaxKind.EndOfFileToken; token = scanner.scan()) {
  200. if (token === ts.SyntaxKind.StringLiteral) {
  201. if (!expectValue) {
  202. return undefined;
  203. }
  204. result.push(scanner.getTokenValue());
  205. expectValue = false;
  206. }
  207. else if (token === ts.SyntaxKind.CommaToken) {
  208. if (expectValue) {
  209. return undefined;
  210. }
  211. expectValue = true;
  212. }
  213. else if (token !== ts.SyntaxKind.WhitespaceTrivia) {
  214. // only ignore whitespace, other trivia like comments makes this function bail out
  215. return undefined;
  216. }
  217. }
  218. return result.length === 0 ? undefined : result;
  219. }
  220. function createMarkupFromErrors(code, lintErrors) {
  221. lintErrors.sort(lintError_1.errorComparator);
  222. var codeText = code.split("\n");
  223. var errorLinesForCodeText = codeText.map(function () { return []; });
  224. for (var _i = 0, lintErrors_1 = lintErrors; _i < lintErrors_1.length; _i++) {
  225. var error = lintErrors_1[_i];
  226. var startPos = error.startPos, endPos = error.endPos, message = error.message;
  227. if (startPos.line === endPos.line) {
  228. // single line error
  229. errorLinesForCodeText[startPos.line].push(new lines_1.EndErrorLine(startPos.col, endPos.col, message));
  230. }
  231. else {
  232. // multiline error
  233. errorLinesForCodeText[startPos.line].push(new lines_1.MultilineErrorLine(startPos.col));
  234. for (var lineNo = startPos.line + 1; lineNo < endPos.line; ++lineNo) {
  235. errorLinesForCodeText[lineNo].push(new lines_1.MultilineErrorLine(0));
  236. }
  237. errorLinesForCodeText[endPos.line].push(new lines_1.EndErrorLine(0, endPos.col, message));
  238. }
  239. }
  240. return utils_1.flatMap(codeText, function (line, i) { return [line].concat(utils_1.mapDefined(errorLinesForCodeText[i], function (err) { return lines_1.printLine(err, line); })); }).join("\n");
  241. }
  242. exports.createMarkupFromErrors = createMarkupFromErrors;
  243. /* tslint:enable:object-literal-sort-keys */
  244. function createCodeLineNoToErrorsMap(lines) {
  245. var errorLinesForCodeLine = [];
  246. for (var _i = 0, lines_3 = lines; _i < lines_3.length; _i++) {
  247. var line = lines_3[_i];
  248. if (line instanceof lines_1.CodeLine) {
  249. errorLinesForCodeLine.push([]);
  250. }
  251. else if (line instanceof lines_1.ErrorLine) {
  252. errorLinesForCodeLine[errorLinesForCodeLine.length - 1].push(line);
  253. }
  254. }
  255. return errorLinesForCodeLine;
  256. }
  257. function isValidErrorMarkupContinuation(errorLinesForCodeLines, lineNo) {
  258. return lineNo < errorLinesForCodeLines.length
  259. && errorLinesForCodeLines[lineNo].length !== 0
  260. && errorLinesForCodeLines[lineNo][0].startCol === 0;
  261. }