UNPKG

@microsoft/api-extractor

Version:

Validatation, documentation, and auditing for the exported API of a TypeScript package

219 lines (217 loc) 8.49 kB
/* tslint:disable:no-bitwise */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var PrettyPrinter_1 = require("./PrettyPrinter"); var TypeScriptHelpers = (function () { function TypeScriptHelpers() { } /** * Returns the Symbol for the provided Declaration. This is a workaround for a missing * feature of the TypeScript Compiler API. It is the only apparent way to reach * certain data structures, and seems to always work, but is not officially documented. * * @returns The associated Symbol. If there is no semantic information (e.g. if the * declaration is an extra semicolon somewhere), then "undefined" is returned. */ TypeScriptHelpers.tryGetSymbolForDeclaration = function (declaration) { /* tslint:disable:no-any */ var symbol = declaration.symbol; /* tslint:enable:no-any */ return symbol; }; /** * Same semantics as tryGetSymbolForDeclaration(), but throws an exception if the symbol * cannot be found. */ TypeScriptHelpers.getSymbolForDeclaration = function (declaration) { var symbol = TypeScriptHelpers.tryGetSymbolForDeclaration(declaration); if (!symbol) { PrettyPrinter_1.default.throwUnexpectedSyntaxError(declaration, 'Unable to determine the semantic information for this declaration'); } return symbol; }; /** * Returns the JSDoc comments associated with the specified node, if any. * * Example: * "This \n is \n a comment" from "\/** This\r\n* is\r\n* a comment *\/ */ TypeScriptHelpers.getJsDocComments = function (node, errorLogger) { var jsDoc = ''; // tslint:disable-next-line:no-any var nodeJsDocObjects = node.jsDoc; if (nodeJsDocObjects && nodeJsDocObjects.length > 0) { // Use the JSDoc closest to the declaration var lastJsDocIndex = nodeJsDocObjects.length - 1; var jsDocFullText = nodeJsDocObjects[lastJsDocIndex].getText(); var jsDocLines = jsDocFullText.split(TypeScriptHelpers.newLineRegEx); var jsDocStartSeqExists = TypeScriptHelpers.jsDocStartRegEx.test(jsDocLines[0].toString()); // Report error for each missing sequence seperately if (!jsDocStartSeqExists) { errorLogger('JsDoc comment must begin with a \"/**\" sequence.'); return ''; } var jsDocEndSeqExists = TypeScriptHelpers.jsDocEndRegEx.test(jsDocLines[jsDocLines.length - 1].toString()); if (!jsDocEndSeqExists) { errorLogger('JsDoc comment must end with a \"*/\" sequence.'); return ''; } jsDoc = TypeScriptHelpers.removeJsDocSequences(jsDocLines); } return jsDoc; }; /** * Helper function to remove the comment stars ('/**'. '*', '/*) from lines of comment text. * * Example: * ["\/**", "*This \n", "*is \n", "*a comment", "*\/"] to "This \n is \n a comment" */ TypeScriptHelpers.removeJsDocSequences = function (textLines) { // Remove '/**' textLines[0] = textLines[0].replace(TypeScriptHelpers.jsDocStartRegEx, ''); if (textLines[0] === '') { textLines.shift(); } // Remove '*/' textLines[textLines.length - 1] = textLines[textLines.length - 1].replace(TypeScriptHelpers.jsDocEndRegEx, ''); if (textLines[textLines.length - 1] === '') { textLines.pop(); } // Remove the leading '*' from any intermediate lines if (textLines.length > 0) { for (var i = 0; i < textLines.length; i++) { textLines[i] = textLines[i].replace(TypeScriptHelpers.jsDocIntermediateRegEx, ''); } } return textLines.join('\n'); }; /** * Similar to calling string.split() with a RegExp, except that the delimiters * are included in the result. * * Example: _splitStringWithRegEx("ABCDaFG", /A/gi) -> [ "A", "BCD", "a", "FG" ] * Example: _splitStringWithRegEx("", /A/gi) -> [ ] * Example: _splitStringWithRegEx("", /A?/gi) -> [ "" ] */ TypeScriptHelpers.splitStringWithRegEx = function (text, regExp) { if (!regExp.global) { throw new Error('RegExp must have the /g flag'); } if (text === undefined) { return []; } var result = []; var index = 0; var match; do { match = regExp.exec(text); if (match) { if (match.index > index) { result.push(text.substring(index, match.index)); } var matchText = match[0]; if (!matchText) { // It might be interesting to support matching e.g. '\b', but regExp.exec() // doesn't seem to iterate properly in this situation. throw new Error('The regular expression must match a nonzero number of characters'); } result.push(matchText); index = regExp.lastIndex; } } while (match && regExp.global); if (index < text.length) { result.push(text.substr(index)); } return result; }; /** * Extracts the body of a TypeScript comment and returns it. */ // Examples: // "/**\n * this is\n * a test\n */\n" --> "this is\na test" // "/** single line comment */" --> "single line comment" TypeScriptHelpers.extractCommentContent = function (text) { var lines = text.replace('\r', '').split('\n'); var State; (function (State) { State[State["Start"] = 0] = "Start"; State[State["Body"] = 1] = "Body"; State[State["Done"] = 2] = "Done"; State[State["Error"] = 3] = "Error"; })(State || (State = {})); var state = State.Start; var startRegExp = /^\s*\/\*\*+ ?/; var bodyRegExp = /^\s*\* ?/; var endRegExp = /^\s*\*+\/\s*$/; var singleLineEndRegExp = / ?\*+\/\s*$/; var content = ''; for (var _i = 0, lines_1 = lines; _i < lines_1.length; _i++) { var line = lines_1[_i]; if (line.trim().length === 0) { continue; } var modified = line; switch (state) { case State.Start: if (line.match(startRegExp)) { modified = line.replace(startRegExp, ''); if (modified.match(singleLineEndRegExp)) { modified = modified.replace(singleLineEndRegExp, ''); state = State.Done; } else { state = State.Body; } } else { state = State.Error; } break; case State.Body: if (line.match(endRegExp)) { modified = line.replace(endRegExp, ''); state = State.Done; } else if (line.match(bodyRegExp)) { modified = line.replace(bodyRegExp, ''); } else { state = State.Error; } break; case State.Done: state = State.Error; break; } if (modified !== '') { if (content !== '') { content += '\n'; } content += modified; } } if (state !== State.Done) { return '[ERROR PARSING COMMENT]'; } return content; }; return TypeScriptHelpers; }()); /** * Splits by the characters '\r\n'. */ TypeScriptHelpers.newLineRegEx = /\r\n|\n/g; /** * Start sequence is '/**'. */ TypeScriptHelpers.jsDocStartRegEx = /^\s*\/\*\*\s?/g; /** * End sequence is '*\/'. */ TypeScriptHelpers.jsDocEndRegEx = /\s*\*\/\s*$/g; /** * Intermediate lines of JSDoc comment character. */ TypeScriptHelpers.jsDocIntermediateRegEx = /^\s*[*]\s?/g; exports.default = TypeScriptHelpers; //# sourceMappingURL=TypeScriptHelpers.js.map