diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index c5c2164..0000000 --- a/.eslintrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "airbnb", - "rules": { - "func-names": 0, - "strict": 0, - "prefer-arrow-callback": 0, - "prefer-rest-params": 0, - "no-plusplus": 0 - } -} diff --git a/.travis.yml b/.travis.yml index 45b11a5..5b394e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,4 @@ language: node_js node_js: - 8 -before_install: npm i -g gulp \ No newline at end of file +# before_install: npm i -g gulp \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index c785623..208db56 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -27,7 +27,7 @@ "type": "node", "request": "launch", "name": "Launch Program", - "program": "${workspaceFolder}/main.js" + "program": "${workspaceFolder}/build/index.js" } ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index f47f36d..e69de29 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,12 +0,0 @@ -{ - "files.exclude": { - "**/.git": true, - "**/.svn": true, - "**/.hg": true, - "**/.DS_Store": true, - "**/*.js.map": true, - "**/*.js": { - "when": "$(basename).ts" - } - } -} \ No newline at end of file diff --git a/README.md b/README.md index c92bb37..6b2847a 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,97 @@ -# Parser +# mr-doc-parser [![Build Status](https://travis-ci.org/mr-doc/mr-doc-parser.svg?branch=master)](https://travis-ci.org/mr-doc/mr-doc-parser) -## Specification +## Introduction -A parser must implement the following interface: +This is the official parser for Mr. Doc. The parser uses [node-tree-sitter](https://github.com/tree-sitter/node-tree-sitter) to parse different programming languages. It also uses [xdoc-parser](https://github.com/iwatakeshi/xdoc-parser) to parse JSDoc-like syntaxes in a comment. Note that `mr-doc-parser` is in alpha. Thus, the algorithms may change over time. At the moment, there are two languages that are supported by `mr-doc-parser`: JavaScript and TypeScript. More languages can be added as long as [tree-sitter](https://github.com/tree-sitter) can parse them. + +## Creating a Language Parser + +### Extend the Language Parser + +To create a parser, simply extend an abstract class named `Parser` in `src/lang/common/parser.ts`: ```typescript -interface IParser { - parse: (file: IFile) => IParseResult +abstract class Parser { + constructor(source: Source, options: any) {/* ... */} + abstract parse(): ASTNode[] + abstract get tree(): Tree +} +``` + +**Note**: See the [JavaScript parser](./src/lang/javascript/index.ts) for an example. + +### Extend the Language Visitor + +The next step is to walk the tree that parsed by `tree-sitter` and to wrap each node as an `Node` type. +Bear in mind that `tree-sitter` keeps its tree as a DOM-like structure. + +It may seem like an additional step to re-wrap the nodes, but it is a necessary step to make visiting each node a bit easier: + +```ts +// Example for JavaScript +import * as Parser from 'tree-sitter'; +import * as JavaScript from 'tree-sitter-javascript'; +import walk from 'path to [src/utils/walk]' + +// Create the parser +const parser = new Parser(); +// Set the langauge +parser.setLangauge(JavaScript); +// Parse the source code +const tree = parser.parse('...'); +// Walk the tree +const nodes = walk(tree); + +``` + +Once the tree is wrapped, we need to extend the abstract `Visitor` visitor: + +```ts +abstract class Visitor { + abstract getAST(): ASTNode[] + abstract visitNode(node: SyntaxNode, properties?: object): ASTNode + abstract visitChildren(nodes: SyntaxNode[], properties?: object): ASTNode[] } ``` -The output should be in the following format: +**Note**: See the [JavaScript visitor](./src/lang/javascript/visitor.ts) for an example. + +### Return the AST + +The last step is to return the AST. To do so, simply use the `createNode` function and return an array of `ASTNode` type: ```typescript -interface IParseResult { - comments: IComment[], +interface ASTNode extends TextRange { + /** + * @property - The type of node. + */ type: string, - file: IFile + /** + * @property - The context string. + */ + text: string, + /** + * @property - The node's children. + */ + children: ASTNode[] | undefined[], + /** + * @property - The context node that a comment node refers to. + */ + context: ASTNode, + /** + * @property - The properties that a ASTNode may possess. + */ + properties?: object + /** + * @property - The parsed XDoc comment. + */ + comment?: { + markdown: RemarkNode, + documentation: Partial + } } ``` - -These interfaces are defined in `parser/interface.ts`. \ No newline at end of file diff --git a/build/corpus/example.d.ts b/build/corpus/example.d.ts new file mode 100644 index 0000000..e0a4604 --- /dev/null +++ b/build/corpus/example.d.ts @@ -0,0 +1,6 @@ +export declare namespace X { + /** + * + */ + function name(...args: any[]): void; +} diff --git a/build/corpus/example.js b/build/corpus/example.js new file mode 100644 index 0000000..7204ff3 --- /dev/null +++ b/build/corpus/example.js @@ -0,0 +1,12 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var X; +(function (X) { + /** + * + */ + function name(...args) { + } + X.name = name; +})(X = exports.X || (exports.X = {})); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhhbXBsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL2NvcnB1cy9leGFtcGxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsSUFBaUIsQ0FBQyxDQU9qQjtBQVBELFdBQWlCLENBQUM7SUFDaEI7O09BRUc7SUFDSCxTQUFnQixJQUFJLENBQUMsR0FBRyxJQUFJO0lBRTVCLENBQUM7SUFGZSxNQUFJLE9BRW5CLENBQUE7QUFDSCxDQUFDLEVBUGdCLENBQUMsR0FBRCxTQUFDLEtBQUQsU0FBQyxRQU9qQiIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBuYW1lc3BhY2UgWCB7XG4gIC8qKlxuICAgKiBcbiAgICovXG4gIGV4cG9ydCBmdW5jdGlvbiBuYW1lKC4uLmFyZ3MpIHtcbiAgICBcbiAgfVxufSJdfQ== \ No newline at end of file diff --git a/build/index.d.ts b/build/index.d.ts new file mode 100644 index 0000000..e76644c --- /dev/null +++ b/build/index.d.ts @@ -0,0 +1,28 @@ +import Source from './src/interfaces/Source'; +import Parser from './src/lang/common/parser'; +import { Tree } from 'tree-sitter'; +/** + * A class that parses a source code and generates an AST. + * + * @class Parser + * @implements IParser + * + * # Example + * + * ```js + * const parser = new Parser({ + * name: '...', + * path: '....', + * text: '...' + * }, { language: 'typescript' }); + * + * const result = parser.parse(); + * + * ``` + */ +export default class DocParser extends Parser { + private parser; + constructor(source: Source, options?: object); + parse: () => import("./src/interfaces/ASTNode").default[]; + readonly tree: Tree; +} diff --git a/build/index.js b/build/index.js new file mode 100644 index 0000000..6b0193d --- /dev/null +++ b/build/index.js @@ -0,0 +1,37 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const ParserFactory_1 = require("./src/ParserFactory"); +const parser_1 = require("./src/lang/common/parser"); +/** + * A class that parses a source code and generates an AST. + * + * @class Parser + * @implements IParser + * + * # Example + * + * ```js + * const parser = new Parser({ + * name: '...', + * path: '....', + * text: '...' + * }, { language: 'typescript' }); + * + * const result = parser.parse(); + * + * ``` + */ +class DocParser extends parser_1.default { + constructor(source, options) { + super(source, options); + this.parse = () => { + return this.parser.parse(); + }; + this.parser = (new ParserFactory_1.default(this.source, this.options)).getParser(); + } + get tree() { + return this.parser.tree; + } +} +exports.default = DocParser; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUNBLHVEQUFnRDtBQUNoRCxxREFBOEM7QUFHOUM7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtCRztBQUNILE1BQXFCLFNBQVUsU0FBUSxnQkFBTTtJQUczQyxZQUFZLE1BQWMsRUFBRSxPQUFnQjtRQUMxQyxLQUFLLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFBO1FBR3hCLFVBQUssR0FBRyxHQUFHLEVBQUU7WUFDWCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUE7UUFDNUIsQ0FBQyxDQUFBO1FBSkMsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksdUJBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFNBQVMsRUFBRSxDQUFDO0lBQzNFLENBQUM7SUFJRCxJQUFJLElBQUk7UUFDTixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDO0lBQzFCLENBQUM7Q0FDRjtBQWJELDRCQWFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFNvdXJjZSBmcm9tICcuL3NyYy9pbnRlcmZhY2VzL1NvdXJjZSc7XG5pbXBvcnQgUGFyc2VyRmFjdG9yeSBmcm9tICcuL3NyYy9QYXJzZXJGYWN0b3J5JztcbmltcG9ydCBQYXJzZXIgZnJvbSAnLi9zcmMvbGFuZy9jb21tb24vcGFyc2VyJztcbmltcG9ydCB7IFRyZWUgfSBmcm9tICd0cmVlLXNpdHRlcic7XG5cbi8qKlxuICogQSBjbGFzcyB0aGF0IHBhcnNlcyBhIHNvdXJjZSBjb2RlIGFuZCBnZW5lcmF0ZXMgYW4gQVNULlxuICogXG4gKiBAY2xhc3MgUGFyc2VyXG4gKiBAaW1wbGVtZW50cyBJUGFyc2VyXG4gKiBcbiAqICMgRXhhbXBsZVxuICogXG4gKiBgYGBqc1xuICogY29uc3QgcGFyc2VyID0gbmV3IFBhcnNlcih7XG4gKiAgbmFtZTogJy4uLicsXG4gKiAgcGF0aDogJy4uLi4nLFxuICogIHRleHQ6ICcuLi4nXG4gKiB9LCB7IGxhbmd1YWdlOiAndHlwZXNjcmlwdCcgfSk7XG4gKiBcbiAqIGNvbnN0IHJlc3VsdCA9IHBhcnNlci5wYXJzZSgpO1xuICogXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRG9jUGFyc2VyIGV4dGVuZHMgUGFyc2VyIHtcblxuICBwcml2YXRlIHBhcnNlcjogUGFyc2VyO1xuICBjb25zdHJ1Y3Rvcihzb3VyY2U6IFNvdXJjZSwgb3B0aW9ucz86IG9iamVjdCkge1xuICAgIHN1cGVyKHNvdXJjZSwgb3B0aW9ucylcbiAgICB0aGlzLnBhcnNlciA9IChuZXcgUGFyc2VyRmFjdG9yeSh0aGlzLnNvdXJjZSwgdGhpcy5vcHRpb25zKSkuZ2V0UGFyc2VyKCk7XG4gIH1cbiAgcGFyc2UgPSAoKSA9PiB7XG4gICAgcmV0dXJuIHRoaXMucGFyc2VyLnBhcnNlKClcbiAgfVxuICBnZXQgdHJlZSAoKTogVHJlZSB7XG4gICAgcmV0dXJuIHRoaXMucGFyc2VyLnRyZWU7XG4gIH1cbn1cbiJdfQ== \ No newline at end of file diff --git a/build/src/ParserFactory.d.ts b/build/src/ParserFactory.d.ts new file mode 100644 index 0000000..fb0bf8c --- /dev/null +++ b/build/src/ParserFactory.d.ts @@ -0,0 +1,8 @@ +import Source from "./interfaces/Source"; +import Parser from "./lang/common/parser"; +export default class ParserFactory { + private source; + private options; + constructor(file: Source, options?: any); + getParser: () => Parser; +} diff --git a/build/src/ParserFactory.js b/build/src/ParserFactory.js new file mode 100644 index 0000000..9a0b6b3 --- /dev/null +++ b/build/src/ParserFactory.js @@ -0,0 +1,28 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const javascript_1 = require("./lang/javascript"); +const typescript_1 = require("./lang/typescript"); +class ParserFactory { + constructor(file, options = {}) { + this.options = { + language: 'JavaScript' + }; + this.getParser = () => { + switch (this.options.language.toLowerCase()) { + case 'js': + case 'javascript': + return new javascript_1.default(this.source, this.options); + case 'ts': + case 'typescript': + return new typescript_1.default(this.source, this.options); + default: + console.log(`[mr-doc]: No parser for ${this.options.language} exists.`); + break; + } + }; + this.source = file; + Object.assign(this.options, options); + } +} +exports.default = ParserFactory; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGFyc2VyRmFjdG9yeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9QYXJzZXJGYWN0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQ0Esa0RBQWlEO0FBQ2pELGtEQUFpRDtBQUdqRCxNQUFxQixhQUFhO0lBS2hDLFlBQVksSUFBWSxFQUFFLFVBQWUsRUFBRTtRQUhuQyxZQUFPLEdBQUc7WUFDaEIsUUFBUSxFQUFFLFlBQVk7U0FDdkIsQ0FBQTtRQU1ELGNBQVMsR0FBRyxHQUFXLEVBQUU7WUFDdkIsUUFBUSxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsRUFBRTtnQkFDM0MsS0FBSyxJQUFJLENBQUM7Z0JBQ1YsS0FBSyxZQUFZO29CQUNmLE9BQU8sSUFBSSxvQkFBZ0IsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDekQsS0FBSyxJQUFJLENBQUM7Z0JBQ1YsS0FBSyxZQUFZO29CQUNmLE9BQU8sSUFBSSxvQkFBZ0IsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDekQ7b0JBQ0EsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLFVBQVUsQ0FBQyxDQUFBO29CQUNyRSxNQUFNO2FBQ1Q7UUFDSCxDQUFDLENBQUE7UUFoQkMsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUM7UUFDbkIsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFBO0lBQ3RDLENBQUM7Q0FlRjtBQXZCRCxnQ0F1QkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgU291cmNlIGZyb20gXCIuL2ludGVyZmFjZXMvU291cmNlXCI7XG5pbXBvcnQgSmF2YVNjcmlwdFBhcnNlciBmcm9tIFwiLi9sYW5nL2phdmFzY3JpcHRcIjtcbmltcG9ydCBUeXBlU2NyaXB0UGFyc2VyIGZyb20gJy4vbGFuZy90eXBlc2NyaXB0JztcbmltcG9ydCBQYXJzZXIgZnJvbSBcIi4vbGFuZy9jb21tb24vcGFyc2VyXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFBhcnNlckZhY3Rvcnkge1xuICBwcml2YXRlIHNvdXJjZTogU291cmNlXG4gIHByaXZhdGUgb3B0aW9ucyA9IHtcbiAgICBsYW5ndWFnZTogJ0phdmFTY3JpcHQnXG4gIH1cbiAgY29uc3RydWN0b3IoZmlsZTogU291cmNlLCBvcHRpb25zOiBhbnkgPSB7fSkge1xuICAgIHRoaXMuc291cmNlID0gZmlsZTtcbiAgICBPYmplY3QuYXNzaWduKHRoaXMub3B0aW9ucywgb3B0aW9ucylcbiAgfVxuXG4gIGdldFBhcnNlciA9ICgpOiBQYXJzZXIgPT4ge1xuICAgIHN3aXRjaCAodGhpcy5vcHRpb25zLmxhbmd1YWdlLnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgIGNhc2UgJ2pzJzpcbiAgICAgIGNhc2UgJ2phdmFzY3JpcHQnOlxuICAgICAgICByZXR1cm4gbmV3IEphdmFTY3JpcHRQYXJzZXIodGhpcy5zb3VyY2UsIHRoaXMub3B0aW9ucyk7XG4gICAgICBjYXNlICd0cyc6XG4gICAgICBjYXNlICd0eXBlc2NyaXB0JzpcbiAgICAgICAgcmV0dXJuIG5ldyBUeXBlU2NyaXB0UGFyc2VyKHRoaXMuc291cmNlLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgZGVmYXVsdDpcbiAgICAgIGNvbnNvbGUubG9nKGBbbXItZG9jXTogTm8gcGFyc2VyIGZvciAke3RoaXMub3B0aW9ucy5sYW5ndWFnZX0gZXhpc3RzLmApXG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxufSJdfQ== \ No newline at end of file diff --git a/build/src/interfaces/ASTNode.d.ts b/build/src/interfaces/ASTNode.d.ts new file mode 100644 index 0000000..9fa1bc6 --- /dev/null +++ b/build/src/interfaces/ASTNode.d.ts @@ -0,0 +1,32 @@ +import TextRange from "./TextRange"; +import { RemarkNode } from "xdoc-parser/src/XDocParser"; +import { DocumentationNode } from "xdoc-parser/src/XDocASTNode"; +export default interface ASTNode extends TextRange { + /** + * @property - The type of node. + */ + type: string; + /** + * @property - The context string. + */ + text: string; + /** + * @property - The node's children. + */ + children: ASTNode[] | undefined[]; + /** + * @property - The context node that a comment node refers to. + */ + context: ASTNode; + /** + * @property - The properties that a ASTNode may possess. + */ + properties?: object; + /** + * @property - The parsed XDoc comment. + */ + comment?: { + markdown: RemarkNode; + documentation: Partial; + }; +} diff --git a/build/src/interfaces/ASTNode.js b/build/src/interfaces/ASTNode.js new file mode 100644 index 0000000..06d8a70 --- /dev/null +++ b/build/src/interfaces/ASTNode.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQVNUTm9kZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9pbnRlcmZhY2VzL0FTVE5vZGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBUZXh0UmFuZ2UgZnJvbSBcIi4vVGV4dFJhbmdlXCI7XG5pbXBvcnQgeyBSZW1hcmtOb2RlIH0gZnJvbSBcInhkb2MtcGFyc2VyL3NyYy9YRG9jUGFyc2VyXCI7XG5pbXBvcnQgeyBEb2N1bWVudGF0aW9uTm9kZSB9IGZyb20gXCJ4ZG9jLXBhcnNlci9zcmMvWERvY0FTVE5vZGVcIjtcblxuZXhwb3J0IGRlZmF1bHQgaW50ZXJmYWNlIEFTVE5vZGUgZXh0ZW5kcyBUZXh0UmFuZ2Uge1xuICAvKipcbiAgICogQHByb3BlcnR5IC0gVGhlIHR5cGUgb2Ygbm9kZS5cbiAgICovXG4gIHR5cGU6IHN0cmluZyxcbiAgLyoqXG4gICAqIEBwcm9wZXJ0eSAtIFRoZSBjb250ZXh0IHN0cmluZy5cbiAgICovXG4gIHRleHQ6IHN0cmluZyxcbiAgLyoqXG4gICAqIEBwcm9wZXJ0eSAtIFRoZSBub2RlJ3MgY2hpbGRyZW4uXG4gICAqL1xuICBjaGlsZHJlbjogQVNUTm9kZVtdIHwgdW5kZWZpbmVkW10sXG4gIC8qKlxuICAgKiBAcHJvcGVydHkgLSBUaGUgY29udGV4dCBub2RlIHRoYXQgYSBjb21tZW50IG5vZGUgcmVmZXJzIHRvLlxuICAgKi9cbiAgY29udGV4dDogQVNUTm9kZSxcbiAgLyoqXG4gICAqIEBwcm9wZXJ0eSAtIFRoZSBwcm9wZXJ0aWVzIHRoYXQgYSBBU1ROb2RlIG1heSBwb3NzZXNzLlxuICAgKi9cbiAgcHJvcGVydGllcz86IG9iamVjdFxuICAvKipcbiAgICogQHByb3BlcnR5IC0gVGhlIHBhcnNlZCBYRG9jIGNvbW1lbnQuXG4gICAqL1xuICBjb21tZW50Pzoge1xuICAgIG1hcmtkb3duOiBSZW1hcmtOb2RlLFxuICAgIGRvY3VtZW50YXRpb246IFBhcnRpYWw8RG9jdW1lbnRhdGlvbk5vZGU+XG4gIH1cbn0iXX0= \ No newline at end of file diff --git a/build/src/interfaces/Source.d.ts b/build/src/interfaces/Source.d.ts new file mode 100644 index 0000000..d0f8af4 --- /dev/null +++ b/build/src/interfaces/Source.d.ts @@ -0,0 +1,5 @@ +export default interface Source { + name: string; + path: string; + text: string; +} diff --git a/build/src/interfaces/Source.js b/build/src/interfaces/Source.js new file mode 100644 index 0000000..0d8ff4e --- /dev/null +++ b/build/src/interfaces/Source.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU291cmNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2ludGVyZmFjZXMvU291cmNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgZGVmYXVsdCBpbnRlcmZhY2UgU291cmNlIHtcbiAgbmFtZTogc3RyaW5nLFxuICBwYXRoOiBzdHJpbmcsXG4gIHRleHQ6IHN0cmluZ1xufSJdfQ== \ No newline at end of file diff --git a/build/src/interfaces/TextRange.d.ts b/build/src/interfaces/TextRange.d.ts new file mode 100644 index 0000000..142d2e1 --- /dev/null +++ b/build/src/interfaces/TextRange.d.ts @@ -0,0 +1,37 @@ +/** + * An interface that represents a range. + * + * @interface Range + */ +export interface Range { + start: number; + end: number; +} +/** + * An interface that represents the positional + * and locational ranges of a source code. + * + * @interface TextRange + */ +export default interface TextRange { + /** + * Represents a context's start and end position. + * @property position: { + * start: number, + * end: number + * } + */ + position: Range; + /** + * Represents a context's row and column location. + * + * @location: { + * row: Range, + * column: Range + * } + */ + location: { + row: Range; + column: Range; + }; +} diff --git a/build/src/interfaces/TextRange.js b/build/src/interfaces/TextRange.js new file mode 100644 index 0000000..51ef572 --- /dev/null +++ b/build/src/interfaces/TextRange.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVGV4dFJhbmdlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2ludGVyZmFjZXMvVGV4dFJhbmdlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJcbi8qKlxuICogQW4gaW50ZXJmYWNlIHRoYXQgcmVwcmVzZW50cyBhIHJhbmdlLlxuICogXG4gKiBAaW50ZXJmYWNlIFJhbmdlXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmFuZ2Uge1xuICBzdGFydDogbnVtYmVyLFxuICBlbmQ6IG51bWJlclxufVxuXG4vKipcbiAqIEFuIGludGVyZmFjZSB0aGF0IHJlcHJlc2VudHMgdGhlIHBvc2l0aW9uYWwgXG4gKiBhbmQgbG9jYXRpb25hbCByYW5nZXMgb2YgYSBzb3VyY2UgY29kZS5cbiAqIFxuICogQGludGVyZmFjZSBUZXh0UmFuZ2VcbiAqL1xuZXhwb3J0IGRlZmF1bHQgaW50ZXJmYWNlIFRleHRSYW5nZSB7XG4gIC8qKlxuICAgKiBSZXByZXNlbnRzIGEgY29udGV4dCdzIHN0YXJ0IGFuZCBlbmQgcG9zaXRpb24uXG4gICAqIEBwcm9wZXJ0eSBwb3NpdGlvbjoge1xuICAgKiAgc3RhcnQ6IG51bWJlcixcbiAgICogIGVuZDogbnVtYmVyXG4gICAqIH1cbiAgICovXG4gIHBvc2l0aW9uOiBSYW5nZVxuICAvKipcbiAgICogUmVwcmVzZW50cyBhIGNvbnRleHQncyByb3cgYW5kIGNvbHVtbiBsb2NhdGlvbi5cbiAgICogXG4gICAqIEBsb2NhdGlvbjoge1xuICAgKiAgcm93OiBSYW5nZSxcbiAgICogIGNvbHVtbjogUmFuZ2VcbiAgICogfVxuICAgKi9cbiAgbG9jYXRpb246IHtcbiAgICByb3c6IFJhbmdlLFxuICAgIGNvbHVtbjogUmFuZ2VcbiAgfVxufSJdfQ== \ No newline at end of file diff --git a/build/src/lang/common/ast.d.ts b/build/src/lang/common/ast.d.ts new file mode 100644 index 0000000..428c5c2 --- /dev/null +++ b/build/src/lang/common/ast.d.ts @@ -0,0 +1,9 @@ +import { SyntaxNode } from "tree-sitter"; +import Source from "../../interfaces/Source"; +import ASTNode from "../../interfaces/ASTNode"; +export declare function isASTNode(object: object): object is ASTNode; +export declare function createASTNode(source: Source, node: SyntaxNode): ASTNode; +export declare function createASTNode(source: Source, node: SyntaxNode, properties: object): any; +export declare function createASTNode(source: Source, node: SyntaxNode, children: object[]): ASTNode; +export declare function createASTNode(source: Source, node: SyntaxNode, children: object[], properties: object): any; +export declare function createASTNode(source: Source, node: SyntaxNode, context: ASTNode, document: boolean): ASTNode; diff --git a/build/src/lang/common/ast.js b/build/src/lang/common/ast.js new file mode 100644 index 0000000..380f1e9 --- /dev/null +++ b/build/src/lang/common/ast.js @@ -0,0 +1,29 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const text_1 = require("../../utils/text"); +const range_1 = require("../../utils/range"); +const xdoc_parser_1 = require("xdoc-parser"); +const _ = require("lodash"); +function isASTNode(object) { + return object && 'type' in object && 'text' in object && 'children' in object; +} +exports.isASTNode = isASTNode; +function createASTNode(source, node, arg1, arg2) { + let context, children = [], document = typeof arg2 === 'boolean' && arg2 === true, properties; + if (_.isPlainObject(arg1) && !isASTNode(arg1)) { + properties = arg1; + } + else if (_.isPlainObject(arg1) && isASTNode(arg1)) { + context = arg1; + } + else if (_.isArray(arg1)) { + children = arg1; + } + if (_.isPlainObject(arg2)) { + properties = arg2; + } + return Object.assign({ type: node.type, text: text_1.text(source, node) }, range_1.default(node), { context, + children, comment: document ? xdoc_parser_1.default(source.text).parse() : undefined, properties }); +} +exports.createASTNode = createASTNode; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xhbmcvY29tbW9uL2FzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUNBLDJDQUF3QztBQUN4Qyw2Q0FBc0M7QUFFdEMsNkNBQStCO0FBQy9CLDRCQUEyQjtBQUczQixTQUFnQixTQUFTLENBQUMsTUFBYztJQUN0QyxPQUFPLE1BQU0sSUFBSSxNQUFNLElBQUksTUFBTSxJQUFJLE1BQU0sSUFBSSxNQUFNLElBQUksVUFBVSxJQUFJLE1BQU0sQ0FBQztBQUNoRixDQUFDO0FBRkQsOEJBRUM7QUFPRCxTQUFnQixhQUFhLENBQUMsTUFBYyxFQUFFLElBQWdCLEVBQUUsSUFBVSxFQUFFLElBQVU7SUFFcEYsSUFBSSxPQUFPLEVBQUUsUUFBUSxHQUFHLEVBQUUsRUFBRSxRQUFRLEdBQUcsT0FBTyxJQUFJLEtBQUssU0FBUyxJQUFJLElBQUksS0FBSyxJQUFJLEVBQUUsVUFBVSxDQUFDO0lBRTlGLElBQUksQ0FBQyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRTtRQUM3QyxVQUFVLEdBQUcsSUFBSSxDQUFDO0tBQ25CO1NBQU0sSUFBSSxDQUFDLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRTtRQUNuRCxPQUFPLEdBQUcsSUFBSSxDQUFDO0tBQ2hCO1NBQU0sSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFO1FBQzFCLFFBQVEsR0FBRyxJQUFJLENBQUM7S0FDakI7SUFFRCxJQUFJLENBQUMsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLEVBQUU7UUFDekIsVUFBVSxHQUFHLElBQUksQ0FBQztLQUNuQjtJQUVELHVCQUNFLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxFQUNmLElBQUksRUFBRSxXQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxJQUNyQixlQUFLLENBQUMsSUFBSSxDQUFDLElBQ2QsT0FBTztRQUNQLFFBQVEsRUFDUixPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxxQkFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUN6RCxVQUFVLElBQ1g7QUFDSCxDQUFDO0FBekJELHNDQXlCQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFN5bnRheE5vZGUgfSBmcm9tIFwidHJlZS1zaXR0ZXJcIjtcbmltcG9ydCB7IHRleHQgfSBmcm9tIFwiLi4vLi4vdXRpbHMvdGV4dFwiO1xuaW1wb3J0IHJhbmdlIGZyb20gXCIuLi8uLi91dGlscy9yYW5nZVwiO1xuaW1wb3J0IFNvdXJjZSBmcm9tIFwiLi4vLi4vaW50ZXJmYWNlcy9Tb3VyY2VcIjtcbmltcG9ydCB4ZG9jIGZyb20gJ3hkb2MtcGFyc2VyJztcbmltcG9ydCAqIGFzIF8gZnJvbSAnbG9kYXNoJ1xuaW1wb3J0IEFTVE5vZGUgZnJvbSBcIi4uLy4uL2ludGVyZmFjZXMvQVNUTm9kZVwiO1xuXG5leHBvcnQgZnVuY3Rpb24gaXNBU1ROb2RlKG9iamVjdDogb2JqZWN0KTogb2JqZWN0IGlzIEFTVE5vZGUge1xuICByZXR1cm4gb2JqZWN0ICYmICd0eXBlJyBpbiBvYmplY3QgJiYgJ3RleHQnIGluIG9iamVjdCAmJiAnY2hpbGRyZW4nIGluIG9iamVjdDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUFTVE5vZGUoc291cmNlOiBTb3VyY2UsIG5vZGU6IFN5bnRheE5vZGUpOiBBU1ROb2RlXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlQVNUTm9kZShzb3VyY2U6IFNvdXJjZSwgbm9kZTogU3ludGF4Tm9kZSwgcHJvcGVydGllczogb2JqZWN0KVxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUFTVE5vZGUoc291cmNlOiBTb3VyY2UsIG5vZGU6IFN5bnRheE5vZGUsIGNoaWxkcmVuOiBvYmplY3RbXSk6IEFTVE5vZGVcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVBU1ROb2RlKHNvdXJjZTogU291cmNlLCBub2RlOiBTeW50YXhOb2RlLCBjaGlsZHJlbjogb2JqZWN0W10sIHByb3BlcnRpZXM6IG9iamVjdClcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVBU1ROb2RlKHNvdXJjZTogU291cmNlLCBub2RlOiBTeW50YXhOb2RlLCBjb250ZXh0OiBBU1ROb2RlLCBkb2N1bWVudDogYm9vbGVhbik6IEFTVE5vZGVcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVBU1ROb2RlKHNvdXJjZTogU291cmNlLCBub2RlOiBTeW50YXhOb2RlLCBhcmcxPzogYW55LCBhcmcyPzogYW55KTogQVNUTm9kZSB7XG5cbiAgbGV0IGNvbnRleHQsIGNoaWxkcmVuID0gW10sIGRvY3VtZW50ID0gdHlwZW9mIGFyZzIgPT09ICdib29sZWFuJyAmJiBhcmcyID09PSB0cnVlLCBwcm9wZXJ0aWVzO1xuXG4gIGlmIChfLmlzUGxhaW5PYmplY3QoYXJnMSkgJiYgIWlzQVNUTm9kZShhcmcxKSkge1xuICAgIHByb3BlcnRpZXMgPSBhcmcxO1xuICB9IGVsc2UgaWYgKF8uaXNQbGFpbk9iamVjdChhcmcxKSAmJiBpc0FTVE5vZGUoYXJnMSkpIHtcbiAgICBjb250ZXh0ID0gYXJnMTtcbiAgfSBlbHNlIGlmIChfLmlzQXJyYXkoYXJnMSkpIHtcbiAgICBjaGlsZHJlbiA9IGFyZzE7XG4gIH1cblxuICBpZiAoXy5pc1BsYWluT2JqZWN0KGFyZzIpKSB7XG4gICAgcHJvcGVydGllcyA9IGFyZzI7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIHR5cGU6IG5vZGUudHlwZSxcbiAgICB0ZXh0OiB0ZXh0KHNvdXJjZSwgbm9kZSksXG4gICAgLi4ucmFuZ2Uobm9kZSksXG4gICAgY29udGV4dCxcbiAgICBjaGlsZHJlbixcbiAgICBjb21tZW50OiBkb2N1bWVudCA/IHhkb2Moc291cmNlLnRleHQpLnBhcnNlKCkgOiB1bmRlZmluZWQsXG4gICAgcHJvcGVydGllcyxcbiAgfVxufVxuIl19 \ No newline at end of file diff --git a/build/src/lang/common/node.d.ts b/build/src/lang/common/node.d.ts new file mode 100644 index 0000000..9509b1f --- /dev/null +++ b/build/src/lang/common/node.d.ts @@ -0,0 +1,13 @@ +import { SyntaxNode } from "tree-sitter"; +import Visitor from "./visitor"; +export interface TreeSitterNode { + visit(visitor: Visitor): void; +} +/** + * A class that wraps a SyntaxNode as a Node + */ +export declare class Node implements TreeSitterNode { + syntaxNode: SyntaxNode; + constructor(syntaxNode: SyntaxNode); + visit: (visitor: Visitor) => void; +} diff --git a/build/src/lang/common/node.js b/build/src/lang/common/node.js new file mode 100644 index 0000000..59098b1 --- /dev/null +++ b/build/src/lang/common/node.js @@ -0,0 +1,15 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +/** + * A class that wraps a SyntaxNode as a Node + */ +class Node { + constructor(syntaxNode) { + this.syntaxNode = syntaxNode; + this.visit = (visitor) => { + visitor.visitNode(this.syntaxNode); + }; + } +} +exports.Node = Node; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9sYW5nL2NvbW1vbi9ub2RlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBT0E7O0dBRUc7QUFDSCxNQUFhLElBQUk7SUFDZixZQUFtQixVQUFzQjtRQUF0QixlQUFVLEdBQVYsVUFBVSxDQUFZO1FBQ3pDLFVBQUssR0FBRyxDQUFDLE9BQWdCLEVBQVEsRUFBRTtZQUNqQyxPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNyQyxDQUFDLENBQUE7SUFINEMsQ0FBQztDQUkvQztBQUxELG9CQUtDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgU3ludGF4Tm9kZSB9IGZyb20gXCJ0cmVlLXNpdHRlclwiO1xuaW1wb3J0IFZpc2l0b3IgZnJvbSBcIi4vdmlzaXRvclwiO1xuXG5leHBvcnQgaW50ZXJmYWNlIFRyZWVTaXR0ZXJOb2RlIHtcbiAgdmlzaXQodmlzaXRvcjogVmlzaXRvcik6IHZvaWRcbn1cblxuLyoqXG4gKiBBIGNsYXNzIHRoYXQgd3JhcHMgYSBTeW50YXhOb2RlIGFzIGEgTm9kZVxuICovXG5leHBvcnQgY2xhc3MgTm9kZSBpbXBsZW1lbnRzIFRyZWVTaXR0ZXJOb2RlIHtcbiAgY29uc3RydWN0b3IocHVibGljIHN5bnRheE5vZGU6IFN5bnRheE5vZGUpIHsgfVxuICB2aXNpdCA9ICh2aXNpdG9yOiBWaXNpdG9yKTogdm9pZCA9PiB7XG4gICAgdmlzaXRvci52aXNpdE5vZGUodGhpcy5zeW50YXhOb2RlKTtcbiAgfVxufSJdfQ== \ No newline at end of file diff --git a/build/src/lang/common/parser.d.ts b/build/src/lang/common/parser.d.ts new file mode 100644 index 0000000..185028f --- /dev/null +++ b/build/src/lang/common/parser.d.ts @@ -0,0 +1,19 @@ +import Source from "../../interfaces/Source"; +import { Tree } from "tree-sitter"; +import ASTNode from "../../interfaces/ASTNode"; +import { LogOptions } from "mr-doc-utils"; +import { XDocParserOptions } from "xdoc-parser/src/XDocParser"; +export interface ParserOptions { + log: LogOptions; + documentation: XDocParserOptions; + language?: string; +} +export default abstract class Parser { + private source_; + protected options: ParserOptions; + constructor(source: Source, options: Partial); + readonly source: Source; + readonly language: string; + abstract parse(): ASTNode[]; + abstract readonly tree: Tree; +} diff --git a/build/src/lang/common/parser.js b/build/src/lang/common/parser.js new file mode 100644 index 0000000..4be1694 --- /dev/null +++ b/build/src/lang/common/parser.js @@ -0,0 +1,18 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +class Parser { + constructor(source, options) { + this.source_ = source; + this.options = Object.assign((options || {}), { + log: { + enabled: true, + levels: ['info', 'warn', 'error'] + }, + documentation: {}, + }); + } + get source() { return this.source_; } + get language() { return this.options.language; } +} +exports.default = Parser; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFyc2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xhbmcvY29tbW9uL3BhcnNlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQVlBLE1BQThCLE1BQU07SUFHbEMsWUFBWSxNQUFjLEVBQUUsT0FBK0I7UUFDekQsSUFBSSxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUM7UUFDdEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQyxFQUFFO1lBQzVDLEdBQUcsRUFBRTtnQkFDSCxPQUFPLEVBQUUsSUFBSTtnQkFDYixNQUFNLEVBQUUsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLE9BQU8sQ0FBQzthQUNwQjtZQUNmLGFBQWEsRUFBRSxFQUNPO1NBQ3ZCLENBQUMsQ0FBQztJQUNMLENBQUM7SUFDRCxJQUFJLE1BQU0sS0FBYSxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQzdDLElBQUksUUFBUSxLQUFhLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO0NBR3pEO0FBbEJELHlCQWtCQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBTb3VyY2UgZnJvbSBcIi4uLy4uL2ludGVyZmFjZXMvU291cmNlXCI7XG5pbXBvcnQgeyBUcmVlIH0gZnJvbSBcInRyZWUtc2l0dGVyXCI7XG5pbXBvcnQgQVNUTm9kZSBmcm9tIFwiLi4vLi4vaW50ZXJmYWNlcy9BU1ROb2RlXCI7XG5pbXBvcnQgeyBMb2dPcHRpb25zIH0gZnJvbSBcIm1yLWRvYy11dGlsc1wiO1xuaW1wb3J0IHsgWERvY1BhcnNlck9wdGlvbnMgfSBmcm9tIFwieGRvYy1wYXJzZXIvc3JjL1hEb2NQYXJzZXJcIjtcblxuZXhwb3J0IGludGVyZmFjZSBQYXJzZXJPcHRpb25zIHtcbiAgbG9nOiBMb2dPcHRpb25zLFxuICBkb2N1bWVudGF0aW9uOiBYRG9jUGFyc2VyT3B0aW9ucyxcbiAgbGFuZ3VhZ2U/OiBzdHJpbmdcbn1cblxuZXhwb3J0IGRlZmF1bHQgYWJzdHJhY3QgY2xhc3MgUGFyc2VyIHtcbiAgcHJpdmF0ZSBzb3VyY2VfOiBTb3VyY2VcbiAgcHJvdGVjdGVkIG9wdGlvbnM6IFBhcnNlck9wdGlvbnNcbiAgY29uc3RydWN0b3Ioc291cmNlOiBTb3VyY2UsIG9wdGlvbnM6IFBhcnRpYWw8UGFyc2VyT3B0aW9ucz4pIHtcbiAgICB0aGlzLnNvdXJjZV8gPSBzb3VyY2U7XG4gICAgdGhpcy5vcHRpb25zID0gT2JqZWN0LmFzc2lnbigob3B0aW9ucyB8fCB7fSksIHtcbiAgICAgIGxvZzoge1xuICAgICAgICBlbmFibGVkOiB0cnVlLFxuICAgICAgICBsZXZlbHM6IFsnaW5mbycsICd3YXJuJywgJ2Vycm9yJ11cbiAgICAgIH0gYXMgTG9nT3B0aW9ucyxcbiAgICAgIGRvY3VtZW50YXRpb246IHtcbiAgICAgIH0gYXMgWERvY1BhcnNlck9wdGlvbnMsXG4gICAgfSk7XG4gIH1cbiAgZ2V0IHNvdXJjZSgpOiBTb3VyY2UgeyByZXR1cm4gdGhpcy5zb3VyY2VfOyB9XG4gIGdldCBsYW5ndWFnZSgpOiBzdHJpbmcgeyByZXR1cm4gdGhpcy5vcHRpb25zLmxhbmd1YWdlOyB9XG4gIGFic3RyYWN0IHBhcnNlKCk6IEFTVE5vZGVbXVxuICBhYnN0cmFjdCBnZXQgdHJlZSgpOiBUcmVlXG59Il19 \ No newline at end of file diff --git a/build/src/lang/common/visitor.d.ts b/build/src/lang/common/visitor.d.ts new file mode 100644 index 0000000..74c8f51 --- /dev/null +++ b/build/src/lang/common/visitor.d.ts @@ -0,0 +1,17 @@ +import { SyntaxNode } from "tree-sitter"; +import ASTNode from "../../interfaces/ASTNode"; +import { LogOptions } from "mr-doc-utils"; +import { XDocParserOptions } from "xdoc-parser/src/XDocParser"; +import ParserLogger from "../../utils/log"; +export interface VisitorOptions { + log: LogOptions; + documentation: XDocParserOptions; +} +export default abstract class Visitor { + protected options: Partial; + protected logger: ParserLogger; + constructor(options?: Partial); + abstract getAST(): ASTNode[]; + abstract visitNode(node: SyntaxNode, properties?: object): ASTNode; + abstract visitChildren(nodes: SyntaxNode[], properties?: object): ASTNode[]; +} diff --git a/build/src/lang/common/visitor.js b/build/src/lang/common/visitor.js new file mode 100644 index 0000000..32762f1 --- /dev/null +++ b/build/src/lang/common/visitor.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const log_1 = require("../../utils/log"); +class Visitor { + constructor(options) { + this.options = options; + this.logger = new log_1.default(this.options.log); + } +} +exports.default = Visitor; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlzaXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9sYW5nL2NvbW1vbi92aXNpdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBSUEseUNBQTJDO0FBTzNDLE1BQThCLE9BQU87SUFHbkMsWUFBWSxPQUFpQztRQUMzQyxJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUN2QixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksYUFBWSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDbkQsQ0FBQztDQUlGO0FBVkQsMEJBVUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBTeW50YXhOb2RlIH0gZnJvbSBcInRyZWUtc2l0dGVyXCI7XG5pbXBvcnQgQVNUTm9kZSBmcm9tIFwiLi4vLi4vaW50ZXJmYWNlcy9BU1ROb2RlXCI7XG5pbXBvcnQgeyBMb2dPcHRpb25zLCBMb2dJbnRlcmZhY2UgfSBmcm9tIFwibXItZG9jLXV0aWxzXCI7XG5pbXBvcnQgeyBYRG9jUGFyc2VyT3B0aW9ucyB9IGZyb20gXCJ4ZG9jLXBhcnNlci9zcmMvWERvY1BhcnNlclwiO1xuaW1wb3J0IFBhcnNlckxvZ2dlciBmcm9tIFwiLi4vLi4vdXRpbHMvbG9nXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVmlzaXRvck9wdGlvbnMge1xuICBsb2c6IExvZ09wdGlvbnMsXG4gIGRvY3VtZW50YXRpb246IFhEb2NQYXJzZXJPcHRpb25zXG59XG5cbmV4cG9ydCBkZWZhdWx0IGFic3RyYWN0IGNsYXNzIFZpc2l0b3Ige1xuICBwcm90ZWN0ZWQgb3B0aW9uczogUGFydGlhbDxWaXNpdG9yT3B0aW9ucz5cbiAgcHJvdGVjdGVkIGxvZ2dlcjogUGFyc2VyTG9nZ2VyXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM/OiBQYXJ0aWFsPFZpc2l0b3JPcHRpb25zPikge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5sb2dnZXIgPSBuZXcgUGFyc2VyTG9nZ2VyKHRoaXMub3B0aW9ucy5sb2cpO1xuICB9XG4gIGFic3RyYWN0IGdldEFTVCgpOiBBU1ROb2RlW11cbiAgYWJzdHJhY3QgdmlzaXROb2RlKG5vZGU6IFN5bnRheE5vZGUsIHByb3BlcnRpZXM/OiBvYmplY3QpOiBBU1ROb2RlXG4gIGFic3RyYWN0IHZpc2l0Q2hpbGRyZW4obm9kZXM6IFN5bnRheE5vZGVbXSwgcHJvcGVydGllcz86IG9iamVjdCk6IEFTVE5vZGVbXVxufSJdfQ== \ No newline at end of file diff --git a/build/src/lang/javascript/index.d.ts b/build/src/lang/javascript/index.d.ts new file mode 100644 index 0000000..6a7e4a6 --- /dev/null +++ b/build/src/lang/javascript/index.d.ts @@ -0,0 +1,20 @@ +import * as TreeSitter from 'tree-sitter'; +import Parser from '../common/parser'; +import Source from '../../interfaces/Source'; +import ASTNode from '../../interfaces/ASTNode'; +/** + * A class that parses JavaScript comments. + * + * # API + * + * @class JavaScriptParser + * @implements IParser + * @export default + */ +export default class JavaScriptParser extends Parser { + private parser; + private tree_; + constructor(source: Source, options: any); + parse(): ASTNode[]; + readonly tree: TreeSitter.Tree; +} diff --git a/build/src/lang/javascript/index.js b/build/src/lang/javascript/index.js new file mode 100644 index 0000000..864d113 --- /dev/null +++ b/build/src/lang/javascript/index.js @@ -0,0 +1,35 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const TreeSitter = require("tree-sitter"); +const JavaScript = require("tree-sitter-javascript"); +const parser_1 = require("../common/parser"); +const visitor_1 = require("./visitor"); +const walk_1 = require("../../utils/walk"); +/** + * A class that parses JavaScript comments. + * + * # API + * + * @class JavaScriptParser + * @implements IParser + * @export default + */ +class JavaScriptParser extends parser_1.default { + constructor(source, options) { + super(source, options); + this.parser = new TreeSitter(); + this.parser.setLanguage(JavaScript); + this.tree_ = this.parser.parse(this.source.text); + } + parse() { + const visitor = new visitor_1.JavaScriptVisitor(this.source, this.options); + const nodes = walk_1.default(this.tree_.rootNode); + nodes.visit(visitor); + return visitor.getAST(); + } + get tree() { + return this.tree_; + } +} +exports.default = JavaScriptParser; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGFuZy9qYXZhc2NyaXB0L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsMENBQTBDO0FBQzFDLHFEQUFxRDtBQUNyRCw2Q0FBc0M7QUFFdEMsdUNBQThDO0FBQzlDLDJDQUFvQztBQUdwQzs7Ozs7Ozs7R0FRRztBQUNILE1BQXFCLGdCQUFpQixTQUFRLGdCQUFNO0lBR2xELFlBQVksTUFBYyxFQUFFLE9BQVk7UUFDdEMsS0FBSyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN2QixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksVUFBVSxFQUFFLENBQUM7UUFDL0IsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDcEMsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFDRCxLQUFLO1FBQ0gsTUFBTSxPQUFPLEdBQUcsSUFBSSwyQkFBaUIsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNqRSxNQUFNLEtBQUssR0FBRyxjQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUN4QyxLQUFLLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQ3BCLE9BQU8sT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFDRCxJQUFJLElBQUk7UUFDTixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDcEIsQ0FBQztDQUNGO0FBbEJELG1DQWtCQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIFRyZWVTaXR0ZXIgZnJvbSAndHJlZS1zaXR0ZXInO1xuaW1wb3J0ICogYXMgSmF2YVNjcmlwdCBmcm9tICd0cmVlLXNpdHRlci1qYXZhc2NyaXB0JztcbmltcG9ydCBQYXJzZXIgZnJvbSAnLi4vY29tbW9uL3BhcnNlcic7XG5pbXBvcnQgU291cmNlIGZyb20gJy4uLy4uL2ludGVyZmFjZXMvU291cmNlJztcbmltcG9ydCB7IEphdmFTY3JpcHRWaXNpdG9yIH0gZnJvbSAnLi92aXNpdG9yJztcbmltcG9ydCB3YWxrIGZyb20gJy4uLy4uL3V0aWxzL3dhbGsnO1xuaW1wb3J0IEFTVE5vZGUgZnJvbSAnLi4vLi4vaW50ZXJmYWNlcy9BU1ROb2RlJztcblxuLyoqXG4gKiBBIGNsYXNzIHRoYXQgcGFyc2VzIEphdmFTY3JpcHQgY29tbWVudHMuXG4gKiBcbiAqICMgQVBJXG4gKiBcbiAqIEBjbGFzcyBKYXZhU2NyaXB0UGFyc2VyXG4gKiBAaW1wbGVtZW50cyBJUGFyc2VyXG4gKiBAZXhwb3J0IGRlZmF1bHRcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgSmF2YVNjcmlwdFBhcnNlciBleHRlbmRzIFBhcnNlciB7XG4gIHByaXZhdGUgcGFyc2VyOiBUcmVlU2l0dGVyO1xuICBwcml2YXRlIHRyZWVfOiBUcmVlU2l0dGVyLlRyZWU7XG4gIGNvbnN0cnVjdG9yKHNvdXJjZTogU291cmNlLCBvcHRpb25zOiBhbnkpIHtcbiAgICBzdXBlcihzb3VyY2UsIG9wdGlvbnMpO1xuICAgIHRoaXMucGFyc2VyID0gbmV3IFRyZWVTaXR0ZXIoKTtcbiAgICB0aGlzLnBhcnNlci5zZXRMYW5ndWFnZShKYXZhU2NyaXB0KTtcbiAgICB0aGlzLnRyZWVfID0gdGhpcy5wYXJzZXIucGFyc2UodGhpcy5zb3VyY2UudGV4dCk7XG4gIH1cbiAgcGFyc2UoKTogQVNUTm9kZVtdIHtcbiAgICBjb25zdCB2aXNpdG9yID0gbmV3IEphdmFTY3JpcHRWaXNpdG9yKHRoaXMuc291cmNlLCB0aGlzLm9wdGlvbnMpO1xuICAgIGNvbnN0IG5vZGVzID0gd2Fsayh0aGlzLnRyZWVfLnJvb3ROb2RlKTtcbiAgICBub2Rlcy52aXNpdCh2aXNpdG9yKVxuICAgIHJldHVybiB2aXNpdG9yLmdldEFTVCgpO1xuICB9XG4gIGdldCB0cmVlICgpOiBUcmVlU2l0dGVyLlRyZWUge1xuICAgIHJldHVybiB0aGlzLnRyZWVfO1xuICB9XG59Il19 \ No newline at end of file diff --git a/build/src/lang/javascript/properties.d.ts b/build/src/lang/javascript/properties.d.ts new file mode 100644 index 0000000..474457c --- /dev/null +++ b/build/src/lang/javascript/properties.d.ts @@ -0,0 +1,14 @@ +export interface JavaScriptProperties { + exports: Partial; + inheritance: Partial; + namespace: boolean; + module: boolean; +} +export interface JavaScriptExports { + export: boolean; + default: boolean; +} +export interface JavaScriptInheritance { + extends: boolean; + implements: boolean; +} diff --git a/build/src/lang/javascript/properties.js b/build/src/lang/javascript/properties.js new file mode 100644 index 0000000..87e17b1 --- /dev/null +++ b/build/src/lang/javascript/properties.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvcGVydGllcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9sYW5nL2phdmFzY3JpcHQvcHJvcGVydGllcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGludGVyZmFjZSBKYXZhU2NyaXB0UHJvcGVydGllcyB7XG4gIGV4cG9ydHM6IFBhcnRpYWw8SmF2YVNjcmlwdEV4cG9ydHM+XG4gIGluaGVyaXRhbmNlOiBQYXJ0aWFsPEphdmFTY3JpcHRJbmhlcml0YW5jZT5cbiAgbmFtZXNwYWNlOiBib29sZWFuLFxuICBtb2R1bGU6IGJvb2xlYW5cbn1cblxuZXhwb3J0IGludGVyZmFjZSBKYXZhU2NyaXB0RXhwb3J0cyB7XG4gIGV4cG9ydDogYm9vbGVhbixcbiAgZGVmYXVsdDogYm9vbGVhblxufVxuXG5leHBvcnQgaW50ZXJmYWNlIEphdmFTY3JpcHRJbmhlcml0YW5jZSB7XG4gIGV4dGVuZHM6IGJvb2xlYW4sXG4gIGltcGxlbWVudHM6IGJvb2xlYW5cbn0iXX0= \ No newline at end of file diff --git a/build/src/lang/javascript/visitor.d.ts b/build/src/lang/javascript/visitor.d.ts new file mode 100644 index 0000000..173dc59 --- /dev/null +++ b/build/src/lang/javascript/visitor.d.ts @@ -0,0 +1,48 @@ +import { SyntaxNode } from "tree-sitter"; +import Source from "../../interfaces/Source"; +import Visitor, { VisitorOptions } from "../common/visitor"; +import ASTNode from "../../interfaces/ASTNode"; +import { JavaScriptProperties } from "./properties"; +/** + * A class that visits ASTNodes from a TypeScript tree. + */ +export declare class JavaScriptVisitor extends Visitor { + private ast; + private source; + constructor(source: Source, options: Partial); + /** + * Determines whether a node has inheritance + */ + private hasInheritance; + /** + * Returns a node's inheritance type + */ + private getInheritanceType; + /** + * Determines whether an export is default + */ + private hasDefaultExport; + /** + * Returns only the comments from a node's children. + */ + private filterType; + getAST(): ASTNode[]; + visitNode: (node: SyntaxNode, properties?: Partial) => ASTNode; + visitChildren: (nodes: SyntaxNode[]) => ASTNode[]; + private visitProgram; + private visitComment; + /** + * Visit the contextual node + * + * # Remark + * + * A node is considered contextual when a comment is visited and the node is its sibling. + */ + private visitContext; + private visitExportStatement; + private visitExpressionStatement; + private visitInternalModule; + private visitClass; + private visitNonTerminal; + private visitTerminal; +} diff --git a/build/src/lang/javascript/visitor.js b/build/src/lang/javascript/visitor.js new file mode 100644 index 0000000..e685162 --- /dev/null +++ b/build/src/lang/javascript/visitor.js @@ -0,0 +1,281 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const ast_1 = require("../common/ast"); +const comment_1 = require("../../utils/comment"); +const sibling_1 = require("../../utils/sibling"); +const _ = require("lodash"); +const log_1 = require("../../utils/log"); +const match_1 = require("../../utils/match"); +const visitor_1 = require("../common/visitor"); +/** + * A class that visits ASTNodes from a TypeScript tree. + */ +class JavaScriptVisitor extends visitor_1.default { + constructor(source, options) { + super(options); + this.ast = []; + /* Visitors */ + this.visitNode = (node, properties) => { + switch (node.type) { + case 'program': + this.ast = this.visitProgram(node); + break; + case 'comment': + return this.visitComment(node); + case 'MISSING': + case 'ERROR': + this.logger.report(this.source, node, log_1.ErrorType.TreeSitterParseError); + break; + default: + /* Match other non-terminals */ + if (match_1.default(node, 'constraint', 'formal_parameters', 'required_parameter', 'rest_parameter', 'type_identifier', 'type_parameters', 'type_parameter', 'type_annotation', 'object_type', 'predefined_type', 'parenthesized_type', 'literal_type', 'intersection_type', 'union_type', 'class_body', 'extends_clause', 'unary_expression', 'binary_expression', 'parenthesized_expression', 'member_expression', 'statement_block', 'return_statement', 'export_statement', 'expression_statement', + // A call_signature can also be a non-contextual node + 'call_signature', 'internal_module', 'if_statement')) { + return this.visitNonTerminal(node, properties); + } + /* Match terminals */ + if (match_1.default(node, 'identifier', 'extends', 'property_identifier', 'accessibility_modifier', 'null', 'undefined', 'return', 'get', 'function', 'namespace', 'if', 'const')) { + return this.visitTerminal(node); + } + this.logger.report(this.source, node, log_1.ErrorType.NodeTypeNotYetSupported); + return; + } + }; + this.visitChildren = (nodes) => { + let children = []; + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + if (!node.type.match(/[<>(){},:;\[\]&|=\+\-\*\/!.]/) && node.type !== '...') { + const child = this.visitNode(node); + if (child) + children.push(child); + } + } + return children; + }; + this.visitProgram = (node) => { + let visited = {}, getStartLocation = (n) => `${n.location.row.start}:${n.location.column.start}`; + // A program can have modules, namespaces, comments as its children + // The first step is to parse all the comments in the root node + let comments = this.visitChildren(this.filterType(node, 'comment')); + // Parse the namespaces in expression_statement + // let namespaces = this.visitChildren(this.filterType(node, 'expression_statement')); + // Parse the export statements in the root node + let exports = this.visitChildren(this.filterType(node, 'export_statement')); + // Get the visited context nodes + for (let i = 0; i < comments.length; i++) { + const comment = comments[i]; + const context = comment; + visited[getStartLocation(context)] = true; + } + // Exports are oddballs since some exports may reference + // a type/node that may have been commented. + // We'll first need to filter the ones we have visited + _.remove(exports, x => visited[getStartLocation(x)]); + // From the ones we have not visited, we'll need to modify + // the node properties of each context in a comment node that + // matches the ones we have not visited. + const matched = {}; + comments = _.compact(comments.map(comment => { + for (let i = 0; i < exports.length; i++) { + const export_ = exports[i]; + const context = comment.context; + for (let j = 0; context && j < context.children.length; j++) { + if (context.children[i] && context.children[i].type === export_.type) { + matched[getStartLocation(export_)] = true; + comment.context.properties = Object.assign(comment.context.properties || {}, export_.properties); + } + } + } + return comment; + })); + // Removed the matched exports + _.remove(exports, x => matched[getStartLocation(x)]); + return [].concat(comments).concat(exports); + }; + this.visitComment = (node) => { + if (comment_1.isJavaDocComment(this.source, node)) { + const nextSibling = sibling_1.sibling(node); + if (nextSibling) { + return ast_1.createASTNode(this.source, node, this.visitContext(nextSibling, {}), true); + } + } + }; + /** + * Visit the contextual node + * + * # Remark + * + * A node is considered contextual when a comment is visited and the node is its sibling. + */ + this.visitContext = (node, properties) => { + switch (node.type) { + case 'export_statement': + return this.visitExportStatement(node, properties); + case 'expression_statement': + return this.visitExpressionStatement(node, properties); + case 'class': + return this.visitClass(node, properties); + case 'function': + case 'call_signature': + case 'method_signature': + case 'property_signature': + case 'public_field_definition': + case 'method_definition': + case 'lexical_declaration': + return this.visitNonTerminal(node, properties); + default: + this.logger.report(this.source, node, log_1.ErrorType.NodeTypeNotYetSupported); + return; + } + }; + /* Statements */ + this.visitExportStatement = (node, properties) => { + let children = node.children, defaultExport = false; + // Remove 'export' since it's always first in the array + children.shift(); + if (this.hasDefaultExport(node)) { + defaultExport = true; + // Remove 'default' export + children.shift(); + } + const child = children.shift(); + return this.visitNode(child, { exports: { export: true, default: defaultExport } }); + }; + this.visitExpressionStatement = (node, properties) => { + let children = node.children; + const child = children.shift(); + if (match_1.default(child, 'internal_module')) { + return this.visitInternalModule(child, properties); + } + if (match_1.default(child, 'function')) { + if (properties) + return this.visitContext(child); + } + return this.visitNonTerminal(child); + }; + /* Modules */ + this.visitInternalModule = (node, properties) => { + let children = node.children.map(child => { + if (match_1.default(child, 'statement_block')) { + return ast_1.createASTNode(this.source, node, this.visitChildren(this.filterType(child, 'comment'))); + } + return this.visitNode(child); + }); + return ast_1.createASTNode(this.source, node, children, Object.assign(properties || {}, { namespace: true })); + }; + /* Declarations */ + this.visitClass = (node, properties) => { + // Since 'interface' or 'class' is always first in the array + // we'll need to remove it from the array. + let children = node.children; + const interface_ = children.shift(); + let extends_ = false, implements_ = false; + if (this.hasInheritance(node)) { + const inheritance = this.getInheritanceType(node); + extends_ = inheritance === 'extends'; + implements_ = inheritance === 'implements'; + } + const node_ = ast_1.createASTNode(this.source, node, this.visitChildren(children), Object.assign(properties || {}, { + inheritance: { + implements: implements_, + extends: extends_ + } + })); + if (match_1.default(node, 'class')) { + return node_; + } + // Overwrite the node type from 'interface_declaration' to 'interface' + return Object.assign(node_, { type: interface_.type }); + }; + /* Non-terminals */ + this.visitNonTerminal = (node, properties) => { + let children = node.children; + // Handle special cases where some non-terminals + // contain comments which is what we care about + if (match_1.default(node, 'class_body', 'object_type')) { + children = this.filterType(node, 'comment'); + } + // Handle special cases where export statements have node properties + if (match_1.default(node, 'export_statement')) { + return this.visitExportStatement(node); + } + // Handle special cases where an internal module contains other nodes + if (match_1.default(node, 'internal_module')) { + return this.visitInternalModule(node, properties); + } + // Handle special cases where an intermal_module can exist in an expression_statement + if (match_1.default(node, 'expression_statement')) { + return this.visitExpressionStatement(node, properties); + } + // Handle special cases where a function has a statement_block + if (match_1.default(node, 'function') || match_1.default(node, 'method_definition')) { + _.remove(children, child => match_1.default(child, 'statement_block')); + return ast_1.createASTNode(this.source, node, this.visitChildren(children), properties); + } + return ast_1.createASTNode(this.source, node, this.visitChildren(children), properties); + }; + /* Terminals */ + this.visitTerminal = (node) => { + return ast_1.createASTNode(this.source, node); + }; + this.source = source; + } + /** + * Determines whether a node has inheritance + */ + hasInheritance(node) { + let inherits = false; + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match_1.default(child, 'extends', 'implements')) { + inherits = true; + } + } + return inherits; + } + /** + * Returns a node's inheritance type + */ + getInheritanceType(node) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match_1.default(child, 'extends')) { + return 'extends'; + } + if (match_1.default(child, 'implements')) { + return 'implements'; + } + } + } + /** + * Determines whether an export is default + */ + hasDefaultExport(node) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match_1.default(child, 'default')) { + return true; + } + } + return false; + } + /** + * Returns only the comments from a node's children. + */ + filterType(node, type) { + let children = []; + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match_1.default(child, type)) { + children.push(child); + } + } + return children; + } + getAST() { + return this.ast; + } +} +exports.JavaScriptVisitor = JavaScriptVisitor; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlzaXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9sYW5nL2phdmFzY3JpcHQvdmlzaXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHVDQUE4QztBQUM5QyxpREFBdUQ7QUFDdkQsaURBQThDO0FBRTlDLDRCQUE0QjtBQUM1Qix5Q0FBaUQ7QUFDakQsNkNBQXNDO0FBRXRDLCtDQUE0RDtBQUk1RDs7R0FFRztBQUNILE1BQWEsaUJBQWtCLFNBQVEsaUJBQU87SUFHNUMsWUFBWSxNQUFjLEVBQUUsT0FBZ0M7UUFDMUQsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBSFQsUUFBRyxHQUFjLEVBQUUsQ0FBQTtRQW9FM0IsZUFBZTtRQUVmLGNBQVMsR0FBRyxDQUNWLElBQWdCLEVBQ2hCLFVBQTBDLEVBQzFDLEVBQUU7WUFDRixRQUFRLElBQUksQ0FBQyxJQUFJLEVBQUU7Z0JBQ2pCLEtBQUssU0FBUztvQkFDWixJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUM7b0JBQ25DLE1BQU07Z0JBQ1IsS0FBSyxTQUFTO29CQUNaLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDakMsS0FBSyxTQUFTLENBQUM7Z0JBQ2YsS0FBSyxPQUFPO29CQUNWLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLGVBQVMsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO29CQUN0RSxNQUFNO2dCQUNSO29CQUVFLCtCQUErQjtvQkFFL0IsSUFBSSxlQUFLLENBQUMsSUFBSSxFQUNaLFlBQVksRUFDWixtQkFBbUIsRUFBRSxvQkFBb0IsRUFBRSxnQkFBZ0IsRUFDM0QsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQUUsZ0JBQWdCLEVBQUUsaUJBQWlCLEVBQ3pFLGFBQWEsRUFBRSxpQkFBaUIsRUFBRSxvQkFBb0IsRUFBRSxjQUFjLEVBQ3RFLG1CQUFtQixFQUFFLFlBQVksRUFDakMsWUFBWSxFQUNaLGdCQUFnQixFQUNoQixrQkFBa0IsRUFBRSxtQkFBbUIsRUFBRSwwQkFBMEIsRUFBRSxtQkFBbUIsRUFDeEYsaUJBQWlCLEVBQUUsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQUUsc0JBQXNCO29CQUNqRixxREFBcUQ7b0JBQ3JELGdCQUFnQixFQUNoQixpQkFBaUIsRUFDakIsY0FBYyxDQUNmLEVBQUU7d0JBQ0QsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFBO3FCQUMvQztvQkFFRCxxQkFBcUI7b0JBQ3JCLElBQUksZUFBSyxDQUFDLElBQUksRUFDWixZQUFZLEVBQUUsU0FBUyxFQUFFLHFCQUFxQixFQUFFLHdCQUF3QixFQUN4RSxNQUFNLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFDN0IsS0FBSyxFQUFFLFVBQVUsRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FDOUMsRUFBRTt3QkFDRCxPQUFPLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7cUJBQ2pDO29CQUVELElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLGVBQVMsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO29CQUN6RSxPQUFPO2FBQ1Y7UUFDSCxDQUFDLENBQUE7UUFFRCxrQkFBYSxHQUFHLENBQUMsS0FBbUIsRUFBYSxFQUFFO1lBQ2pELElBQUksUUFBUSxHQUFjLEVBQUUsQ0FBQztZQUM3QixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtnQkFDckMsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUN0QixJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsOEJBQThCLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLEtBQUssRUFBRTtvQkFDM0UsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDbkMsSUFBSSxLQUFLO3dCQUFFLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7aUJBQ2pDO2FBQ0Y7WUFDRCxPQUFPLFFBQVEsQ0FBQztRQUNsQixDQUFDLENBQUE7UUFFTyxpQkFBWSxHQUFHLENBQUMsSUFBZ0IsRUFBYSxFQUFFO1lBQ3JELElBQUksT0FBTyxHQUFHLEVBQUUsRUFDZCxnQkFBZ0IsR0FBRyxDQUFDLENBQVUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDMUYsbUVBQW1FO1lBQ25FLCtEQUErRDtZQUMvRCxJQUFJLFFBQVEsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7WUFDcEUsK0NBQStDO1lBQy9DLHNGQUFzRjtZQUN0RiwrQ0FBK0M7WUFDL0MsSUFBSSxPQUFPLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxrQkFBa0IsQ0FBQyxDQUFDLENBQUM7WUFFNUUsZ0NBQWdDO1lBQ2hDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO2dCQUN4QyxNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQzVCLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQztnQkFDeEIsT0FBTyxDQUFDLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDO2FBQzNDO1lBRUQsd0RBQXdEO1lBQ3hELDRDQUE0QztZQUM1QyxzREFBc0Q7WUFDdEQsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRXJELDBEQUEwRDtZQUMxRCw2REFBNkQ7WUFDN0Qsd0NBQXdDO1lBQ3hDLE1BQU0sT0FBTyxHQUFHLEVBQUUsQ0FBQztZQUNuQixRQUFRLEdBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FDbEIsUUFBUSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsRUFBRTtnQkFDckIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7b0JBQ3ZDLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDM0IsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQztvQkFDaEMsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsT0FBTyxJQUFJLENBQUMsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTt3QkFDM0QsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLE9BQU8sQ0FBQyxJQUFJLEVBQUU7NEJBQ3BFLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQzs0QkFDMUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxVQUFVLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FDeEMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxVQUFVLElBQUksRUFBRSxFQUNoQyxPQUFPLENBQUMsVUFBVSxDQUNuQixDQUFDO3lCQUNIO3FCQUNGO2lCQUNGO2dCQUNELE9BQU8sT0FBTyxDQUFDO1lBQ2pCLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFFTiw4QkFBOEI7WUFDOUIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBO1lBRXBELE9BQU8sRUFBRSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDN0MsQ0FBQyxDQUFBO1FBRU8saUJBQVksR0FBRyxDQUFDLElBQWdCLEVBQVcsRUFBRTtZQUNuRCxJQUFJLDBCQUFnQixDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUU7Z0JBQ3ZDLE1BQU0sV0FBVyxHQUFHLGlCQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ2xDLElBQUksV0FBVyxFQUFFO29CQUNmLE9BQU8sbUJBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQTtpQkFDbEY7YUFDRjtRQUNILENBQUMsQ0FBQTtRQUVEOzs7Ozs7V0FNRztRQUNLLGlCQUFZLEdBQUcsQ0FBQyxJQUFnQixFQUFFLFVBQTBDLEVBQVcsRUFBRTtZQUMvRixRQUFRLElBQUksQ0FBQyxJQUFJLEVBQUU7Z0JBQ2pCLEtBQUssa0JBQWtCO29CQUNyQixPQUFPLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUM7Z0JBQ3JELEtBQUssc0JBQXNCO29CQUN6QixPQUFPLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUM7Z0JBQ3pELEtBQUssT0FBTztvQkFDVixPQUFPLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFBO2dCQUMxQyxLQUFLLFVBQVUsQ0FBQztnQkFDaEIsS0FBSyxnQkFBZ0IsQ0FBQztnQkFDdEIsS0FBSyxrQkFBa0IsQ0FBQztnQkFDeEIsS0FBSyxvQkFBb0IsQ0FBQztnQkFDMUIsS0FBSyx5QkFBeUIsQ0FBQztnQkFDL0IsS0FBSyxtQkFBbUIsQ0FBQztnQkFDekIsS0FBSyxxQkFBcUI7b0JBQ3hCLE9BQU8sSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQztnQkFDakQ7b0JBQ0UsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsZUFBUyxDQUFDLHVCQUF1QixDQUFDLENBQUM7b0JBQ3pFLE9BQU87YUFDVjtRQUNILENBQUMsQ0FBQTtRQUVELGdCQUFnQjtRQUVSLHlCQUFvQixHQUFHLENBQUMsSUFBZ0IsRUFBRSxVQUEwQyxFQUFXLEVBQUU7WUFDdkcsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLFFBQVEsRUFBRSxhQUFhLEdBQUcsS0FBSyxDQUFDO1lBQ3BELHVEQUF1RDtZQUN2RCxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDakIsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEVBQUU7Z0JBQy9CLGFBQWEsR0FBRyxJQUFJLENBQUM7Z0JBQ3JCLDBCQUEwQjtnQkFDMUIsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDO2FBQ2xCO1lBQ0QsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQy9CLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxPQUFPLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxhQUFhLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDdEYsQ0FBQyxDQUFBO1FBRU8sNkJBQXdCLEdBQUcsQ0FBQyxJQUFnQixFQUFFLFVBQXlDLEVBQVcsRUFBRTtZQUMxRyxJQUFJLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDO1lBQzdCLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUUvQixJQUFJLGVBQUssQ0FBQyxLQUFLLEVBQUUsaUJBQWlCLENBQUMsRUFBRTtnQkFDbkMsT0FBTyxJQUFJLENBQUMsbUJBQW1CLENBQUMsS0FBSyxFQUFFLFVBQVUsQ0FBQyxDQUFBO2FBQ25EO1lBRUQsSUFBSSxlQUFLLENBQUMsS0FBSyxFQUFFLFVBQVUsQ0FBQyxFQUFFO2dCQUM1QixJQUFJLFVBQVU7b0JBQUUsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDO2FBQ2pEO1lBRUQsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDckMsQ0FBQyxDQUFBO1FBRUQsYUFBYTtRQUVMLHdCQUFtQixHQUFHLENBQUMsSUFBZ0IsRUFBRSxVQUEwQyxFQUFXLEVBQUU7WUFDdEcsSUFBSSxRQUFRLEdBQWMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUU7Z0JBQ2xELElBQUksZUFBSyxDQUFDLEtBQUssRUFBRSxpQkFBaUIsQ0FBQyxFQUFFO29CQUNuQyxPQUFPLG1CQUFhLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUE7aUJBQy9GO2dCQUNELE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUMvQixDQUFDLENBQUMsQ0FBQztZQUNILE9BQU8sbUJBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxVQUFVLElBQUksRUFBRSxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztRQUMxRyxDQUFDLENBQUE7UUFHRCxrQkFBa0I7UUFFVixlQUFVLEdBQUcsQ0FBQyxJQUFnQixFQUFFLFVBQTBDLEVBQVcsRUFBRTtZQUM3Riw0REFBNEQ7WUFDNUQsMENBQTBDO1lBQzFDLElBQUksUUFBUSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7WUFDN0IsTUFBTSxVQUFVLEdBQUcsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3BDLElBQUksUUFBUSxHQUFHLEtBQUssRUFBRSxXQUFXLEdBQUcsS0FBSyxDQUFDO1lBQzFDLElBQUksSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsRUFBRTtnQkFDN0IsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxDQUFBO2dCQUNqRCxRQUFRLEdBQUcsV0FBVyxLQUFLLFNBQVMsQ0FBQztnQkFDckMsV0FBVyxHQUFHLFdBQVcsS0FBSyxZQUFZLENBQUM7YUFDNUM7WUFFRCxNQUFNLEtBQUssR0FBRyxtQkFBYSxDQUN6QixJQUFJLENBQUMsTUFBTSxFQUNYLElBQUksRUFDSixJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxFQUM1QixNQUFNLENBQUMsTUFBTSxDQUFDLFVBQVUsSUFBSSxFQUFFLEVBQUU7Z0JBQzlCLFdBQVcsRUFBRTtvQkFDWCxVQUFVLEVBQUUsV0FBVztvQkFDdkIsT0FBTyxFQUFFLFFBQVE7aUJBQ087YUFDM0IsQ0FBQyxDQUFDLENBQUM7WUFFTixJQUFJLGVBQUssQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLEVBQUU7Z0JBQ3hCLE9BQU8sS0FBSyxDQUFDO2FBQ2Q7WUFDRCxzRUFBc0U7WUFDdEUsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQTtRQUN4RCxDQUFDLENBQUE7UUFFRCxtQkFBbUI7UUFFWCxxQkFBZ0IsR0FBRyxDQUFDLElBQWdCLEVBQUUsVUFBMEMsRUFBVyxFQUFFO1lBQ25HLElBQUksUUFBUSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7WUFDN0IsZ0RBQWdEO1lBQ2hELCtDQUErQztZQUMvQyxJQUFJLGVBQUssQ0FBQyxJQUFJLEVBQUUsWUFBWSxFQUFFLGFBQWEsQ0FBQyxFQUFFO2dCQUM1QyxRQUFRLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsU0FBUyxDQUFDLENBQUM7YUFDN0M7WUFDRCxvRUFBb0U7WUFDcEUsSUFBSSxlQUFLLENBQUMsSUFBSSxFQUFFLGtCQUFrQixDQUFDLEVBQUU7Z0JBQ25DLE9BQU8sSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxDQUFDO2FBQ3hDO1lBRUQscUVBQXFFO1lBQ3JFLElBQUksZUFBSyxDQUFDLElBQUksRUFBRSxpQkFBaUIsQ0FBQyxFQUFFO2dCQUNsQyxPQUFPLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUM7YUFDbkQ7WUFFRCxxRkFBcUY7WUFDckYsSUFBSSxlQUFLLENBQUMsSUFBSSxFQUFFLHNCQUFzQixDQUFDLEVBQUU7Z0JBQ3ZDLE9BQU8sSUFBSSxDQUFDLHdCQUF3QixDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQzthQUN4RDtZQUVELDhEQUE4RDtZQUM5RCxJQUFJLGVBQUssQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLElBQUksZUFBSyxDQUFDLElBQUksRUFBRSxtQkFBbUIsQ0FBQyxFQUFFO2dCQUMvRCxDQUFDLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLGVBQUssQ0FBQyxLQUFLLEVBQUUsaUJBQWlCLENBQUMsQ0FBQyxDQUFBO2dCQUM1RCxPQUFPLG1CQUFhLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQzthQUNuRjtZQUVELE9BQU8sbUJBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ3BGLENBQUMsQ0FBQTtRQUVELGVBQWU7UUFFUCxrQkFBYSxHQUFHLENBQUMsSUFBZ0IsRUFBVyxFQUFFO1lBQ3BELE9BQU8sbUJBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFBO1FBQ3pDLENBQUMsQ0FBQTtRQXpVQyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztJQUN2QixDQUFDO0lBRUQ7O09BRUc7SUFDSyxjQUFjLENBQUMsSUFBZ0I7UUFDckMsSUFBSSxRQUFRLEdBQUcsS0FBSyxDQUFDO1FBQ3JCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUM3QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQy9CLElBQUksZUFBSyxDQUFDLEtBQUssRUFBRSxTQUFTLEVBQUUsWUFBWSxDQUFDLEVBQUU7Z0JBQ3pDLFFBQVEsR0FBRyxJQUFJLENBQUM7YUFDakI7U0FDRjtRQUNELE9BQU8sUUFBUSxDQUFBO0lBQ2pCLENBQUM7SUFFRDs7T0FFRztJQUNLLGtCQUFrQixDQUFDLElBQWdCO1FBQ3pDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUM3QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQy9CLElBQUksZUFBSyxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsRUFBRTtnQkFDM0IsT0FBTyxTQUFTLENBQUM7YUFDbEI7WUFFRCxJQUFJLGVBQUssQ0FBQyxLQUFLLEVBQUUsWUFBWSxDQUFDLEVBQUU7Z0JBQzlCLE9BQU8sWUFBWSxDQUFDO2FBQ3JCO1NBQ0Y7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxnQkFBZ0IsQ0FBQyxJQUFnQjtRQUN2QyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDN0MsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMvQixJQUFJLGVBQUssQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLEVBQUU7Z0JBQzNCLE9BQU8sSUFBSSxDQUFDO2FBQ2I7U0FDRjtRQUNELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOztPQUVHO0lBQ0ssVUFBVSxDQUFDLElBQWdCLEVBQUUsSUFBWTtRQUMvQyxJQUFJLFFBQVEsR0FBaUIsRUFBRSxDQUFDO1FBQ2hDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUM3QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQy9CLElBQUksZUFBSyxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsRUFBRTtnQkFDdEIsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQzthQUN0QjtTQUNGO1FBQ0QsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUVELE1BQU07UUFDSixPQUFPLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDbEIsQ0FBQztDQTRRRjtBQS9VRCw4Q0ErVUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjcmVhdGVBU1ROb2RlIH0gZnJvbSBcIi4uL2NvbW1vbi9hc3RcIjtcbmltcG9ydCB7IGlzSmF2YURvY0NvbW1lbnQgfSBmcm9tIFwiLi4vLi4vdXRpbHMvY29tbWVudFwiO1xuaW1wb3J0IHsgc2libGluZyB9IGZyb20gXCIuLi8uLi91dGlscy9zaWJsaW5nXCI7XG5pbXBvcnQgeyBTeW50YXhOb2RlIH0gZnJvbSBcInRyZWUtc2l0dGVyXCI7XG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgbG9nLCB7IEVycm9yVHlwZSB9IGZyb20gXCIuLi8uLi91dGlscy9sb2dcIjtcbmltcG9ydCBtYXRjaCBmcm9tIFwiLi4vLi4vdXRpbHMvbWF0Y2hcIjtcbmltcG9ydCBTb3VyY2UgZnJvbSBcIi4uLy4uL2ludGVyZmFjZXMvU291cmNlXCI7XG5pbXBvcnQgVmlzaXRvciwgeyBWaXNpdG9yT3B0aW9ucyB9IGZyb20gXCIuLi9jb21tb24vdmlzaXRvclwiO1xuaW1wb3J0IEFTVE5vZGUgZnJvbSBcIi4uLy4uL2ludGVyZmFjZXMvQVNUTm9kZVwiO1xuaW1wb3J0IHsgSmF2YVNjcmlwdFByb3BlcnRpZXMsIEphdmFTY3JpcHRJbmhlcml0YW5jZSB9IGZyb20gXCIuL3Byb3BlcnRpZXNcIjtcblxuLyoqXG4gKiBBIGNsYXNzIHRoYXQgdmlzaXRzIEFTVE5vZGVzIGZyb20gYSBUeXBlU2NyaXB0IHRyZWUuXG4gKi9cbmV4cG9ydCBjbGFzcyBKYXZhU2NyaXB0VmlzaXRvciBleHRlbmRzIFZpc2l0b3Ige1xuICBwcml2YXRlIGFzdDogQVNUTm9kZVtdID0gW11cbiAgcHJpdmF0ZSBzb3VyY2U6IFNvdXJjZVxuICBjb25zdHJ1Y3Rvcihzb3VyY2U6IFNvdXJjZSwgb3B0aW9uczogUGFydGlhbDxWaXNpdG9yT3B0aW9ucz4pIHtcbiAgICBzdXBlcihvcHRpb25zKTtcbiAgICB0aGlzLnNvdXJjZSA9IHNvdXJjZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIHdoZXRoZXIgYSBub2RlIGhhcyBpbmhlcml0YW5jZVxuICAgKi9cbiAgcHJpdmF0ZSBoYXNJbmhlcml0YW5jZShub2RlOiBTeW50YXhOb2RlKSB7XG4gICAgbGV0IGluaGVyaXRzID0gZmFsc2U7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBub2RlLmNoaWxkcmVuLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBjaGlsZCA9IG5vZGUuY2hpbGRyZW5baV07XG4gICAgICBpZiAobWF0Y2goY2hpbGQsICdleHRlbmRzJywgJ2ltcGxlbWVudHMnKSkge1xuICAgICAgICBpbmhlcml0cyA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBpbmhlcml0c1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBub2RlJ3MgaW5oZXJpdGFuY2UgdHlwZVxuICAgKi9cbiAgcHJpdmF0ZSBnZXRJbmhlcml0YW5jZVR5cGUobm9kZTogU3ludGF4Tm9kZSkge1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbm9kZS5jaGlsZHJlbi5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgY2hpbGQgPSBub2RlLmNoaWxkcmVuW2ldO1xuICAgICAgaWYgKG1hdGNoKGNoaWxkLCAnZXh0ZW5kcycpKSB7XG4gICAgICAgIHJldHVybiAnZXh0ZW5kcyc7XG4gICAgICB9XG5cbiAgICAgIGlmIChtYXRjaChjaGlsZCwgJ2ltcGxlbWVudHMnKSkge1xuICAgICAgICByZXR1cm4gJ2ltcGxlbWVudHMnO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIHdoZXRoZXIgYW4gZXhwb3J0IGlzIGRlZmF1bHRcbiAgICovXG4gIHByaXZhdGUgaGFzRGVmYXVsdEV4cG9ydChub2RlOiBTeW50YXhOb2RlKTogYm9vbGVhbiB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBub2RlLmNoaWxkcmVuLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBjaGlsZCA9IG5vZGUuY2hpbGRyZW5baV07XG4gICAgICBpZiAobWF0Y2goY2hpbGQsICdkZWZhdWx0JykpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIG9ubHkgdGhlIGNvbW1lbnRzIGZyb20gYSBub2RlJ3MgY2hpbGRyZW4uXG4gICAqL1xuICBwcml2YXRlIGZpbHRlclR5cGUobm9kZTogU3ludGF4Tm9kZSwgdHlwZTogc3RyaW5nKTogU3ludGF4Tm9kZVtdIHtcbiAgICBsZXQgY2hpbGRyZW46IFN5bnRheE5vZGVbXSA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbm9kZS5jaGlsZHJlbi5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgY2hpbGQgPSBub2RlLmNoaWxkcmVuW2ldO1xuICAgICAgaWYgKG1hdGNoKGNoaWxkLCB0eXBlKSkge1xuICAgICAgICBjaGlsZHJlbi5wdXNoKGNoaWxkKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGNoaWxkcmVuO1xuICB9XG5cbiAgZ2V0QVNUKCk6IEFTVE5vZGVbXSB7XG4gICAgcmV0dXJuIHRoaXMuYXN0O1xuICB9XG5cbiAgLyogVmlzaXRvcnMgICovXG5cbiAgdmlzaXROb2RlID0gKFxuICAgIG5vZGU6IFN5bnRheE5vZGUsXG4gICAgcHJvcGVydGllcz86IFBhcnRpYWw8SmF2YVNjcmlwdFByb3BlcnRpZXM+XG4gICkgPT4ge1xuICAgIHN3aXRjaCAobm9kZS50eXBlKSB7XG4gICAgICBjYXNlICdwcm9ncmFtJzpcbiAgICAgICAgdGhpcy5hc3QgPSB0aGlzLnZpc2l0UHJvZ3JhbShub2RlKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdjb21tZW50JzpcbiAgICAgICAgcmV0dXJuIHRoaXMudmlzaXRDb21tZW50KG5vZGUpO1xuICAgICAgY2FzZSAnTUlTU0lORyc6XG4gICAgICBjYXNlICdFUlJPUic6XG4gICAgICAgIHRoaXMubG9nZ2VyLnJlcG9ydCh0aGlzLnNvdXJjZSwgbm9kZSwgRXJyb3JUeXBlLlRyZWVTaXR0ZXJQYXJzZUVycm9yKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuXG4gICAgICAgIC8qIE1hdGNoIG90aGVyIG5vbi10ZXJtaW5hbHMgKi9cblxuICAgICAgICBpZiAobWF0Y2gobm9kZSxcbiAgICAgICAgICAnY29uc3RyYWludCcsXG4gICAgICAgICAgJ2Zvcm1hbF9wYXJhbWV0ZXJzJywgJ3JlcXVpcmVkX3BhcmFtZXRlcicsICdyZXN0X3BhcmFtZXRlcicsXG4gICAgICAgICAgJ3R5cGVfaWRlbnRpZmllcicsICd0eXBlX3BhcmFtZXRlcnMnLCAndHlwZV9wYXJhbWV0ZXInLCAndHlwZV9hbm5vdGF0aW9uJyxcbiAgICAgICAgICAnb2JqZWN0X3R5cGUnLCAncHJlZGVmaW5lZF90eXBlJywgJ3BhcmVudGhlc2l6ZWRfdHlwZScsICdsaXRlcmFsX3R5cGUnLFxuICAgICAgICAgICdpbnRlcnNlY3Rpb25fdHlwZScsICd1bmlvbl90eXBlJyxcbiAgICAgICAgICAnY2xhc3NfYm9keScsXG4gICAgICAgICAgJ2V4dGVuZHNfY2xhdXNlJyxcbiAgICAgICAgICAndW5hcnlfZXhwcmVzc2lvbicsICdiaW5hcnlfZXhwcmVzc2lvbicsICdwYXJlbnRoZXNpemVkX2V4cHJlc3Npb24nLCAnbWVtYmVyX2V4cHJlc3Npb24nLFxuICAgICAgICAgICdzdGF0ZW1lbnRfYmxvY2snLCAncmV0dXJuX3N0YXRlbWVudCcsICdleHBvcnRfc3RhdGVtZW50JywgJ2V4cHJlc3Npb25fc3RhdGVtZW50JyxcbiAgICAgICAgICAvLyBBIGNhbGxfc2lnbmF0dXJlIGNhbiBhbHNvIGJlIGEgbm9uLWNvbnRleHR1YWwgbm9kZVxuICAgICAgICAgICdjYWxsX3NpZ25hdHVyZScsXG4gICAgICAgICAgJ2ludGVybmFsX21vZHVsZScsXG4gICAgICAgICAgJ2lmX3N0YXRlbWVudCdcbiAgICAgICAgKSkge1xuICAgICAgICAgIHJldHVybiB0aGlzLnZpc2l0Tm9uVGVybWluYWwobm9kZSwgcHJvcGVydGllcylcbiAgICAgICAgfVxuXG4gICAgICAgIC8qIE1hdGNoIHRlcm1pbmFscyAqL1xuICAgICAgICBpZiAobWF0Y2gobm9kZSxcbiAgICAgICAgICAnaWRlbnRpZmllcicsICdleHRlbmRzJywgJ3Byb3BlcnR5X2lkZW50aWZpZXInLCAnYWNjZXNzaWJpbGl0eV9tb2RpZmllcicsXG4gICAgICAgICAgJ251bGwnLCAndW5kZWZpbmVkJywgJ3JldHVybicsXG4gICAgICAgICAgJ2dldCcsICdmdW5jdGlvbicsICduYW1lc3BhY2UnLCAnaWYnLCAnY29uc3QnXG4gICAgICAgICkpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy52aXNpdFRlcm1pbmFsKG5vZGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5sb2dnZXIucmVwb3J0KHRoaXMuc291cmNlLCBub2RlLCBFcnJvclR5cGUuTm9kZVR5cGVOb3RZZXRTdXBwb3J0ZWQpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICB9XG5cbiAgdmlzaXRDaGlsZHJlbiA9IChub2RlczogU3ludGF4Tm9kZVtdKTogQVNUTm9kZVtdID0+IHtcbiAgICBsZXQgY2hpbGRyZW46IEFTVE5vZGVbXSA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbm9kZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IG5vZGUgPSBub2Rlc1tpXTtcbiAgICAgIGlmICghbm9kZS50eXBlLm1hdGNoKC9bPD4oKXt9LDo7XFxbXFxdJnw9XFwrXFwtXFwqXFwvIS5dLykgJiYgbm9kZS50eXBlICE9PSAnLi4uJykge1xuICAgICAgICBjb25zdCBjaGlsZCA9IHRoaXMudmlzaXROb2RlKG5vZGUpO1xuICAgICAgICBpZiAoY2hpbGQpIGNoaWxkcmVuLnB1c2goY2hpbGQpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gY2hpbGRyZW47XG4gIH1cblxuICBwcml2YXRlIHZpc2l0UHJvZ3JhbSA9IChub2RlOiBTeW50YXhOb2RlKTogQVNUTm9kZVtdID0+IHtcbiAgICBsZXQgdmlzaXRlZCA9IHt9LFxuICAgICAgZ2V0U3RhcnRMb2NhdGlvbiA9IChuOiBBU1ROb2RlKSA9PiBgJHtuLmxvY2F0aW9uLnJvdy5zdGFydH06JHtuLmxvY2F0aW9uLmNvbHVtbi5zdGFydH1gO1xuICAgIC8vIEEgcHJvZ3JhbSBjYW4gaGF2ZSBtb2R1bGVzLCBuYW1lc3BhY2VzLCBjb21tZW50cyBhcyBpdHMgY2hpbGRyZW5cbiAgICAvLyBUaGUgZmlyc3Qgc3RlcCBpcyB0byBwYXJzZSBhbGwgdGhlIGNvbW1lbnRzIGluIHRoZSByb290IG5vZGVcbiAgICBsZXQgY29tbWVudHMgPSB0aGlzLnZpc2l0Q2hpbGRyZW4odGhpcy5maWx0ZXJUeXBlKG5vZGUsICdjb21tZW50JykpO1xuICAgIC8vIFBhcnNlIHRoZSBuYW1lc3BhY2VzIGluIGV4cHJlc3Npb25fc3RhdGVtZW50XG4gICAgLy8gbGV0IG5hbWVzcGFjZXMgPSB0aGlzLnZpc2l0Q2hpbGRyZW4odGhpcy5maWx0ZXJUeXBlKG5vZGUsICdleHByZXNzaW9uX3N0YXRlbWVudCcpKTtcbiAgICAvLyBQYXJzZSB0aGUgZXhwb3J0IHN0YXRlbWVudHMgaW4gdGhlIHJvb3Qgbm9kZVxuICAgIGxldCBleHBvcnRzID0gdGhpcy52aXNpdENoaWxkcmVuKHRoaXMuZmlsdGVyVHlwZShub2RlLCAnZXhwb3J0X3N0YXRlbWVudCcpKTtcblxuICAgIC8vIEdldCB0aGUgdmlzaXRlZCBjb250ZXh0IG5vZGVzXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb21tZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgY29tbWVudCA9IGNvbW1lbnRzW2ldO1xuICAgICAgY29uc3QgY29udGV4dCA9IGNvbW1lbnQ7XG4gICAgICB2aXNpdGVkW2dldFN0YXJ0TG9jYXRpb24oY29udGV4dCldID0gdHJ1ZTtcbiAgICB9XG5cbiAgICAvLyBFeHBvcnRzIGFyZSBvZGRiYWxscyBzaW5jZSBzb21lIGV4cG9ydHMgbWF5IHJlZmVyZW5jZVxuICAgIC8vIGEgdHlwZS9ub2RlIHRoYXQgbWF5IGhhdmUgYmVlbiBjb21tZW50ZWQuXG4gICAgLy8gV2UnbGwgZmlyc3QgbmVlZCB0byBmaWx0ZXIgdGhlIG9uZXMgd2UgaGF2ZSB2aXNpdGVkXG4gICAgXy5yZW1vdmUoZXhwb3J0cywgeCA9PiB2aXNpdGVkW2dldFN0YXJ0TG9jYXRpb24oeCldKTtcblxuICAgIC8vIEZyb20gdGhlIG9uZXMgd2UgaGF2ZSBub3QgdmlzaXRlZCwgd2UnbGwgbmVlZCB0byBtb2RpZnlcbiAgICAvLyB0aGUgbm9kZSBwcm9wZXJ0aWVzIG9mIGVhY2ggY29udGV4dCBpbiBhIGNvbW1lbnQgbm9kZSB0aGF0XG4gICAgLy8gbWF0Y2hlcyB0aGUgb25lcyB3ZSBoYXZlIG5vdCB2aXNpdGVkLlxuICAgIGNvbnN0IG1hdGNoZWQgPSB7fTtcbiAgICBjb21tZW50cyA9IF8uY29tcGFjdChcbiAgICAgIGNvbW1lbnRzLm1hcChjb21tZW50ID0+IHtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBleHBvcnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgY29uc3QgZXhwb3J0XyA9IGV4cG9ydHNbaV07XG4gICAgICAgICAgY29uc3QgY29udGV4dCA9IGNvbW1lbnQuY29udGV4dDtcbiAgICAgICAgICBmb3IgKGxldCBqID0gMDsgY29udGV4dCAmJiBqIDwgY29udGV4dC5jaGlsZHJlbi5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgaWYgKGNvbnRleHQuY2hpbGRyZW5baV0gJiYgY29udGV4dC5jaGlsZHJlbltpXS50eXBlID09PSBleHBvcnRfLnR5cGUpIHtcbiAgICAgICAgICAgICAgbWF0Y2hlZFtnZXRTdGFydExvY2F0aW9uKGV4cG9ydF8pXSA9IHRydWU7XG4gICAgICAgICAgICAgIGNvbW1lbnQuY29udGV4dC5wcm9wZXJ0aWVzID0gT2JqZWN0LmFzc2lnbihcbiAgICAgICAgICAgICAgICBjb21tZW50LmNvbnRleHQucHJvcGVydGllcyB8fCB7fSxcbiAgICAgICAgICAgICAgICBleHBvcnRfLnByb3BlcnRpZXNcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGNvbW1lbnQ7XG4gICAgICB9KSk7XG5cbiAgICAvLyBSZW1vdmVkIHRoZSBtYXRjaGVkIGV4cG9ydHNcbiAgICBfLnJlbW92ZShleHBvcnRzLCB4ID0+IG1hdGNoZWRbZ2V0U3RhcnRMb2NhdGlvbih4KV0pXG5cbiAgICByZXR1cm4gW10uY29uY2F0KGNvbW1lbnRzKS5jb25jYXQoZXhwb3J0cyk7XG4gIH1cblxuICBwcml2YXRlIHZpc2l0Q29tbWVudCA9IChub2RlOiBTeW50YXhOb2RlKTogQVNUTm9kZSA9PiB7XG4gICAgaWYgKGlzSmF2YURvY0NvbW1lbnQodGhpcy5zb3VyY2UsIG5vZGUpKSB7XG4gICAgICBjb25zdCBuZXh0U2libGluZyA9IHNpYmxpbmcobm9kZSk7XG4gICAgICBpZiAobmV4dFNpYmxpbmcpIHtcbiAgICAgICAgcmV0dXJuIGNyZWF0ZUFTVE5vZGUodGhpcy5zb3VyY2UsIG5vZGUsIHRoaXMudmlzaXRDb250ZXh0KG5leHRTaWJsaW5nLCB7fSksIHRydWUpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFZpc2l0IHRoZSBjb250ZXh0dWFsIG5vZGVcbiAgICogXG4gICAqICMgUmVtYXJrXG4gICAqIFxuICAgKiBBIG5vZGUgaXMgY29uc2lkZXJlZCBjb250ZXh0dWFsIHdoZW4gYSBjb21tZW50IGlzIHZpc2l0ZWQgYW5kIHRoZSBub2RlIGlzIGl0cyBzaWJsaW5nLlxuICAgKi9cbiAgcHJpdmF0ZSB2aXNpdENvbnRleHQgPSAobm9kZTogU3ludGF4Tm9kZSwgcHJvcGVydGllcz86IFBhcnRpYWw8SmF2YVNjcmlwdFByb3BlcnRpZXM+KTogQVNUTm9kZSA9PiB7XG4gICAgc3dpdGNoIChub2RlLnR5cGUpIHtcbiAgICAgIGNhc2UgJ2V4cG9ydF9zdGF0ZW1lbnQnOlxuICAgICAgICByZXR1cm4gdGhpcy52aXNpdEV4cG9ydFN0YXRlbWVudChub2RlLCBwcm9wZXJ0aWVzKTtcbiAgICAgIGNhc2UgJ2V4cHJlc3Npb25fc3RhdGVtZW50JzpcbiAgICAgICAgcmV0dXJuIHRoaXMudmlzaXRFeHByZXNzaW9uU3RhdGVtZW50KG5vZGUsIHByb3BlcnRpZXMpO1xuICAgICAgY2FzZSAnY2xhc3MnOlxuICAgICAgICByZXR1cm4gdGhpcy52aXNpdENsYXNzKG5vZGUsIHByb3BlcnRpZXMpXG4gICAgICBjYXNlICdmdW5jdGlvbic6XG4gICAgICBjYXNlICdjYWxsX3NpZ25hdHVyZSc6XG4gICAgICBjYXNlICdtZXRob2Rfc2lnbmF0dXJlJzpcbiAgICAgIGNhc2UgJ3Byb3BlcnR5X3NpZ25hdHVyZSc6XG4gICAgICBjYXNlICdwdWJsaWNfZmllbGRfZGVmaW5pdGlvbic6XG4gICAgICBjYXNlICdtZXRob2RfZGVmaW5pdGlvbic6XG4gICAgICBjYXNlICdsZXhpY2FsX2RlY2xhcmF0aW9uJzpcbiAgICAgICAgcmV0dXJuIHRoaXMudmlzaXROb25UZXJtaW5hbChub2RlLCBwcm9wZXJ0aWVzKTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRoaXMubG9nZ2VyLnJlcG9ydCh0aGlzLnNvdXJjZSwgbm9kZSwgRXJyb3JUeXBlLk5vZGVUeXBlTm90WWV0U3VwcG9ydGVkKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgfVxuXG4gIC8qIFN0YXRlbWVudHMgKi9cblxuICBwcml2YXRlIHZpc2l0RXhwb3J0U3RhdGVtZW50ID0gKG5vZGU6IFN5bnRheE5vZGUsIHByb3BlcnRpZXM/OiBQYXJ0aWFsPEphdmFTY3JpcHRQcm9wZXJ0aWVzPik6IEFTVE5vZGUgPT4ge1xuICAgIGxldCBjaGlsZHJlbiA9IG5vZGUuY2hpbGRyZW4sIGRlZmF1bHRFeHBvcnQgPSBmYWxzZTtcbiAgICAvLyBSZW1vdmUgJ2V4cG9ydCcgc2luY2UgaXQncyBhbHdheXMgZmlyc3QgaW4gdGhlIGFycmF5XG4gICAgY2hpbGRyZW4uc2hpZnQoKTtcbiAgICBpZiAodGhpcy5oYXNEZWZhdWx0RXhwb3J0KG5vZGUpKSB7XG4gICAgICBkZWZhdWx0RXhwb3J0ID0gdHJ1ZTtcbiAgICAgIC8vIFJlbW92ZSAnZGVmYXVsdCcgZXhwb3J0XG4gICAgICBjaGlsZHJlbi5zaGlmdCgpO1xuICAgIH1cbiAgICBjb25zdCBjaGlsZCA9IGNoaWxkcmVuLnNoaWZ0KCk7XG4gICAgcmV0dXJuIHRoaXMudmlzaXROb2RlKGNoaWxkLCB7IGV4cG9ydHM6IHsgZXhwb3J0OiB0cnVlLCBkZWZhdWx0OiBkZWZhdWx0RXhwb3J0IH0gfSk7XG4gIH1cblxuICBwcml2YXRlIHZpc2l0RXhwcmVzc2lvblN0YXRlbWVudCA9IChub2RlOiBTeW50YXhOb2RlLCBwcm9wZXJ0aWVzOiBQYXJ0aWFsPEphdmFTY3JpcHRQcm9wZXJ0aWVzPik6IEFTVE5vZGUgPT4ge1xuICAgIGxldCBjaGlsZHJlbiA9IG5vZGUuY2hpbGRyZW47XG4gICAgY29uc3QgY2hpbGQgPSBjaGlsZHJlbi5zaGlmdCgpO1xuXG4gICAgaWYgKG1hdGNoKGNoaWxkLCAnaW50ZXJuYWxfbW9kdWxlJykpIHtcbiAgICAgIHJldHVybiB0aGlzLnZpc2l0SW50ZXJuYWxNb2R1bGUoY2hpbGQsIHByb3BlcnRpZXMpXG4gICAgfVxuXG4gICAgaWYgKG1hdGNoKGNoaWxkLCAnZnVuY3Rpb24nKSkge1xuICAgICAgaWYgKHByb3BlcnRpZXMpIHJldHVybiB0aGlzLnZpc2l0Q29udGV4dChjaGlsZCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMudmlzaXROb25UZXJtaW5hbChjaGlsZClcbiAgfVxuXG4gIC8qIE1vZHVsZXMgKi9cblxuICBwcml2YXRlIHZpc2l0SW50ZXJuYWxNb2R1bGUgPSAobm9kZTogU3ludGF4Tm9kZSwgcHJvcGVydGllcz86IFBhcnRpYWw8SmF2YVNjcmlwdFByb3BlcnRpZXM+KTogQVNUTm9kZSA9PiB7XG4gICAgbGV0IGNoaWxkcmVuOiBBU1ROb2RlW10gPSBub2RlLmNoaWxkcmVuLm1hcChjaGlsZCA9PiB7XG4gICAgICBpZiAobWF0Y2goY2hpbGQsICdzdGF0ZW1lbnRfYmxvY2snKSkge1xuICAgICAgICByZXR1cm4gY3JlYXRlQVNUTm9kZSh0aGlzLnNvdXJjZSwgbm9kZSwgdGhpcy52aXNpdENoaWxkcmVuKHRoaXMuZmlsdGVyVHlwZShjaGlsZCwgJ2NvbW1lbnQnKSkpXG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcy52aXNpdE5vZGUoY2hpbGQpO1xuICAgIH0pO1xuICAgIHJldHVybiBjcmVhdGVBU1ROb2RlKHRoaXMuc291cmNlLCBub2RlLCBjaGlsZHJlbiwgT2JqZWN0LmFzc2lnbihwcm9wZXJ0aWVzIHx8IHt9LCB7IG5hbWVzcGFjZTogdHJ1ZSB9KSk7XG4gIH1cblxuXG4gIC8qIERlY2xhcmF0aW9ucyAqL1xuXG4gIHByaXZhdGUgdmlzaXRDbGFzcyA9IChub2RlOiBTeW50YXhOb2RlLCBwcm9wZXJ0aWVzPzogUGFydGlhbDxKYXZhU2NyaXB0UHJvcGVydGllcz4pOiBBU1ROb2RlID0+IHtcbiAgICAvLyBTaW5jZSAnaW50ZXJmYWNlJyBvciAnY2xhc3MnIGlzIGFsd2F5cyBmaXJzdCBpbiB0aGUgYXJyYXlcbiAgICAvLyB3ZSdsbCBuZWVkIHRvIHJlbW92ZSBpdCBmcm9tIHRoZSBhcnJheS5cbiAgICBsZXQgY2hpbGRyZW4gPSBub2RlLmNoaWxkcmVuO1xuICAgIGNvbnN0IGludGVyZmFjZV8gPSBjaGlsZHJlbi5zaGlmdCgpO1xuICAgIGxldCBleHRlbmRzXyA9IGZhbHNlLCBpbXBsZW1lbnRzXyA9IGZhbHNlO1xuICAgIGlmICh0aGlzLmhhc0luaGVyaXRhbmNlKG5vZGUpKSB7XG4gICAgICBjb25zdCBpbmhlcml0YW5jZSA9IHRoaXMuZ2V0SW5oZXJpdGFuY2VUeXBlKG5vZGUpXG4gICAgICBleHRlbmRzXyA9IGluaGVyaXRhbmNlID09PSAnZXh0ZW5kcyc7XG4gICAgICBpbXBsZW1lbnRzXyA9IGluaGVyaXRhbmNlID09PSAnaW1wbGVtZW50cyc7XG4gICAgfVxuXG4gICAgY29uc3Qgbm9kZV8gPSBjcmVhdGVBU1ROb2RlKFxuICAgICAgdGhpcy5zb3VyY2UsXG4gICAgICBub2RlLFxuICAgICAgdGhpcy52aXNpdENoaWxkcmVuKGNoaWxkcmVuKSxcbiAgICAgIE9iamVjdC5hc3NpZ24ocHJvcGVydGllcyB8fCB7fSwge1xuICAgICAgICBpbmhlcml0YW5jZToge1xuICAgICAgICAgIGltcGxlbWVudHM6IGltcGxlbWVudHNfLFxuICAgICAgICAgIGV4dGVuZHM6IGV4dGVuZHNfXG4gICAgICAgIH0gYXMgSmF2YVNjcmlwdEluaGVyaXRhbmNlXG4gICAgICB9KSk7XG5cbiAgICBpZiAobWF0Y2gobm9kZSwgJ2NsYXNzJykpIHtcbiAgICAgIHJldHVybiBub2RlXztcbiAgICB9XG4gICAgLy8gT3ZlcndyaXRlIHRoZSBub2RlIHR5cGUgZnJvbSAnaW50ZXJmYWNlX2RlY2xhcmF0aW9uJyB0byAnaW50ZXJmYWNlJ1xuICAgIHJldHVybiBPYmplY3QuYXNzaWduKG5vZGVfLCB7IHR5cGU6IGludGVyZmFjZV8udHlwZSB9KVxuICB9XG5cbiAgLyogTm9uLXRlcm1pbmFscyAqL1xuXG4gIHByaXZhdGUgdmlzaXROb25UZXJtaW5hbCA9IChub2RlOiBTeW50YXhOb2RlLCBwcm9wZXJ0aWVzPzogUGFydGlhbDxKYXZhU2NyaXB0UHJvcGVydGllcz4pOiBBU1ROb2RlID0+IHtcbiAgICBsZXQgY2hpbGRyZW4gPSBub2RlLmNoaWxkcmVuO1xuICAgIC8vIEhhbmRsZSBzcGVjaWFsIGNhc2VzIHdoZXJlIHNvbWUgbm9uLXRlcm1pbmFsc1xuICAgIC8vIGNvbnRhaW4gY29tbWVudHMgd2hpY2ggaXMgd2hhdCB3ZSBjYXJlIGFib3V0XG4gICAgaWYgKG1hdGNoKG5vZGUsICdjbGFzc19ib2R5JywgJ29iamVjdF90eXBlJykpIHtcbiAgICAgIGNoaWxkcmVuID0gdGhpcy5maWx0ZXJUeXBlKG5vZGUsICdjb21tZW50Jyk7XG4gICAgfVxuICAgIC8vIEhhbmRsZSBzcGVjaWFsIGNhc2VzIHdoZXJlIGV4cG9ydCBzdGF0ZW1lbnRzIGhhdmUgbm9kZSBwcm9wZXJ0aWVzXG4gICAgaWYgKG1hdGNoKG5vZGUsICdleHBvcnRfc3RhdGVtZW50JykpIHtcbiAgICAgIHJldHVybiB0aGlzLnZpc2l0RXhwb3J0U3RhdGVtZW50KG5vZGUpO1xuICAgIH1cblxuICAgIC8vIEhhbmRsZSBzcGVjaWFsIGNhc2VzIHdoZXJlIGFuIGludGVybmFsIG1vZHVsZSBjb250YWlucyBvdGhlciBub2Rlc1xuICAgIGlmIChtYXRjaChub2RlLCAnaW50ZXJuYWxfbW9kdWxlJykpIHtcbiAgICAgIHJldHVybiB0aGlzLnZpc2l0SW50ZXJuYWxNb2R1bGUobm9kZSwgcHJvcGVydGllcyk7XG4gICAgfVxuXG4gICAgLy8gSGFuZGxlIHNwZWNpYWwgY2FzZXMgd2hlcmUgYW4gaW50ZXJtYWxfbW9kdWxlIGNhbiBleGlzdCBpbiBhbiBleHByZXNzaW9uX3N0YXRlbWVudFxuICAgIGlmIChtYXRjaChub2RlLCAnZXhwcmVzc2lvbl9zdGF0ZW1lbnQnKSkge1xuICAgICAgcmV0dXJuIHRoaXMudmlzaXRFeHByZXNzaW9uU3RhdGVtZW50KG5vZGUsIHByb3BlcnRpZXMpO1xuICAgIH1cblxuICAgIC8vIEhhbmRsZSBzcGVjaWFsIGNhc2VzIHdoZXJlIGEgZnVuY3Rpb24gaGFzIGEgc3RhdGVtZW50X2Jsb2NrXG4gICAgaWYgKG1hdGNoKG5vZGUsICdmdW5jdGlvbicpIHx8IG1hdGNoKG5vZGUsICdtZXRob2RfZGVmaW5pdGlvbicpKSB7XG4gICAgICBfLnJlbW92ZShjaGlsZHJlbiwgY2hpbGQgPT4gbWF0Y2goY2hpbGQsICdzdGF0ZW1lbnRfYmxvY2snKSlcbiAgICAgIHJldHVybiBjcmVhdGVBU1ROb2RlKHRoaXMuc291cmNlLCBub2RlLCB0aGlzLnZpc2l0Q2hpbGRyZW4oY2hpbGRyZW4pLCBwcm9wZXJ0aWVzKTtcbiAgICB9XG5cbiAgICByZXR1cm4gY3JlYXRlQVNUTm9kZSh0aGlzLnNvdXJjZSwgbm9kZSwgdGhpcy52aXNpdENoaWxkcmVuKGNoaWxkcmVuKSwgcHJvcGVydGllcyk7XG4gIH1cblxuICAvKiBUZXJtaW5hbHMgKi9cblxuICBwcml2YXRlIHZpc2l0VGVybWluYWwgPSAobm9kZTogU3ludGF4Tm9kZSk6IEFTVE5vZGUgPT4ge1xuICAgIHJldHVybiBjcmVhdGVBU1ROb2RlKHRoaXMuc291cmNlLCBub2RlKVxuICB9XG59Il19 \ No newline at end of file diff --git a/build/src/lang/typescript/index.d.ts b/build/src/lang/typescript/index.d.ts new file mode 100644 index 0000000..f0cec92 --- /dev/null +++ b/build/src/lang/typescript/index.d.ts @@ -0,0 +1,20 @@ +import * as TreeSitter from 'tree-sitter'; +import Parser from '../common/parser'; +import Source from '../../interfaces/Source'; +import ASTNode from '../../interfaces/ASTNode'; +/** + * A class that parses JavaScript comments. + * + * # API + * + * @class JavaScriptParser + * @implements IParser + * @export default + */ +export default class TypeScriptParser extends Parser { + private parser; + private tree_; + constructor(source: Source, options: any); + parse: () => ASTNode[]; + readonly tree: TreeSitter.Tree; +} diff --git a/build/src/lang/typescript/index.js b/build/src/lang/typescript/index.js new file mode 100644 index 0000000..740e298 --- /dev/null +++ b/build/src/lang/typescript/index.js @@ -0,0 +1,35 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const TreeSitter = require("tree-sitter"); +const TypeScript = require("tree-sitter-typescript"); +const parser_1 = require("../common/parser"); +const walk_1 = require("../../utils/walk"); +const visitor_1 = require("./visitor"); +/** + * A class that parses JavaScript comments. + * + * # API + * + * @class JavaScriptParser + * @implements IParser + * @export default + */ +class TypeScriptParser extends parser_1.default { + constructor(source, options) { + super(source, options); + this.parse = () => { + const visitor = new visitor_1.TypeScriptVisitor(this.source, this.options); + const nodes = walk_1.default(this.tree_.rootNode); + nodes.visit(visitor); + return visitor.getAST(); + }; + this.parser = new TreeSitter(); + this.parser.setLanguage(TypeScript); + this.tree_ = this.parser.parse(this.source.text); + } + get tree() { + return this.tree_; + } +} +exports.default = TypeScriptParser; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGFuZy90eXBlc2NyaXB0L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsMENBQTBDO0FBQzFDLHFEQUFxRDtBQUNyRCw2Q0FBc0M7QUFFdEMsMkNBQW9DO0FBQ3BDLHVDQUE4QztBQUk5Qzs7Ozs7Ozs7R0FRRztBQUNILE1BQXFCLGdCQUFpQixTQUFRLGdCQUFNO0lBR2xELFlBQVksTUFBYyxFQUFFLE9BQVk7UUFDdEMsS0FBSyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztRQUt6QixVQUFLLEdBQUcsR0FBYyxFQUFFO1lBQ3RCLE1BQU0sT0FBTyxHQUFHLElBQUksMkJBQWlCLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDakUsTUFBTSxLQUFLLEdBQUcsY0FBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDeEMsS0FBSyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQTtZQUNwQixPQUFPLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUMxQixDQUFDLENBQUE7UUFUQyxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksVUFBVSxFQUFFLENBQUM7UUFDL0IsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDcEMsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFRRCxJQUFJLElBQUk7UUFDTixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDcEIsQ0FBQztDQUNGO0FBbkJELG1DQW1CQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIFRyZWVTaXR0ZXIgZnJvbSAndHJlZS1zaXR0ZXInO1xuaW1wb3J0ICogYXMgVHlwZVNjcmlwdCBmcm9tICd0cmVlLXNpdHRlci10eXBlc2NyaXB0JztcbmltcG9ydCBQYXJzZXIgZnJvbSAnLi4vY29tbW9uL3BhcnNlcic7XG5pbXBvcnQgU291cmNlIGZyb20gJy4uLy4uL2ludGVyZmFjZXMvU291cmNlJztcbmltcG9ydCB3YWxrIGZyb20gJy4uLy4uL3V0aWxzL3dhbGsnO1xuaW1wb3J0IHsgVHlwZVNjcmlwdFZpc2l0b3IgfSBmcm9tICcuL3Zpc2l0b3InO1xuaW1wb3J0IEFTVE5vZGUgZnJvbSAnLi4vLi4vaW50ZXJmYWNlcy9BU1ROb2RlJztcblxuXG4vKipcbiAqIEEgY2xhc3MgdGhhdCBwYXJzZXMgSmF2YVNjcmlwdCBjb21tZW50cy5cbiAqXG4gKiAjIEFQSVxuICpcbiAqIEBjbGFzcyBKYXZhU2NyaXB0UGFyc2VyXG4gKiBAaW1wbGVtZW50cyBJUGFyc2VyXG4gKiBAZXhwb3J0IGRlZmF1bHRcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgVHlwZVNjcmlwdFBhcnNlciBleHRlbmRzIFBhcnNlciB7XG4gIHByaXZhdGUgcGFyc2VyOiBUcmVlU2l0dGVyO1xuICBwcml2YXRlIHRyZWVfOiBUcmVlU2l0dGVyLlRyZWU7XG4gIGNvbnN0cnVjdG9yKHNvdXJjZTogU291cmNlLCBvcHRpb25zOiBhbnkpIHtcbiAgICBzdXBlcihzb3VyY2UsIG9wdGlvbnMpO1xuICAgIHRoaXMucGFyc2VyID0gbmV3IFRyZWVTaXR0ZXIoKTtcbiAgICB0aGlzLnBhcnNlci5zZXRMYW5ndWFnZShUeXBlU2NyaXB0KTtcbiAgICB0aGlzLnRyZWVfID0gdGhpcy5wYXJzZXIucGFyc2UodGhpcy5zb3VyY2UudGV4dCk7XG4gIH1cbiAgcGFyc2UgPSAoKTogQVNUTm9kZVtdID0+IHtcbiAgICBjb25zdCB2aXNpdG9yID0gbmV3IFR5cGVTY3JpcHRWaXNpdG9yKHRoaXMuc291cmNlLCB0aGlzLm9wdGlvbnMpO1xuICAgIGNvbnN0IG5vZGVzID0gd2Fsayh0aGlzLnRyZWVfLnJvb3ROb2RlKTtcbiAgICBub2Rlcy52aXNpdCh2aXNpdG9yKVxuICAgIHJldHVybiB2aXNpdG9yLmdldEFTVCgpO1xuICB9XG5cbiAgZ2V0IHRyZWUgKCk6IFRyZWVTaXR0ZXIuVHJlZSB7XG4gICAgcmV0dXJuIHRoaXMudHJlZV87XG4gIH1cbn1cbiJdfQ== \ No newline at end of file diff --git a/build/src/lang/typescript/properties.d.ts b/build/src/lang/typescript/properties.d.ts new file mode 100644 index 0000000..9477f9c --- /dev/null +++ b/build/src/lang/typescript/properties.d.ts @@ -0,0 +1,14 @@ +export interface TypeScriptProperties { + exports: Partial; + inheritance: Partial; + namespace: boolean; + module: boolean; +} +export interface TypeScriptExports { + export: boolean; + default: boolean; +} +export interface TypeScriptInheritance { + extends: boolean; + implements: boolean; +} diff --git a/build/src/lang/typescript/properties.js b/build/src/lang/typescript/properties.js new file mode 100644 index 0000000..4b4df35 --- /dev/null +++ b/build/src/lang/typescript/properties.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvcGVydGllcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9sYW5nL3R5cGVzY3JpcHQvcHJvcGVydGllcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGludGVyZmFjZSBUeXBlU2NyaXB0UHJvcGVydGllcyB7XG4gIGV4cG9ydHM6IFBhcnRpYWw8VHlwZVNjcmlwdEV4cG9ydHM+XG4gIGluaGVyaXRhbmNlOiBQYXJ0aWFsPFR5cGVTY3JpcHRJbmhlcml0YW5jZT5cbiAgbmFtZXNwYWNlOiBib29sZWFuLFxuICBtb2R1bGU6IGJvb2xlYW5cbn1cblxuZXhwb3J0IGludGVyZmFjZSBUeXBlU2NyaXB0RXhwb3J0cyB7XG4gIGV4cG9ydDogYm9vbGVhbixcbiAgZGVmYXVsdDogYm9vbGVhblxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFR5cGVTY3JpcHRJbmhlcml0YW5jZSB7XG4gIGV4dGVuZHM6IGJvb2xlYW4sXG4gIGltcGxlbWVudHM6IGJvb2xlYW5cbn0iXX0= \ No newline at end of file diff --git a/build/src/lang/typescript/visitor.d.ts b/build/src/lang/typescript/visitor.d.ts new file mode 100644 index 0000000..ebdb198 --- /dev/null +++ b/build/src/lang/typescript/visitor.d.ts @@ -0,0 +1,48 @@ +import { SyntaxNode } from "tree-sitter"; +import Source from "../../interfaces/Source"; +import Visitor, { VisitorOptions } from "../common/visitor"; +import ASTNode from "../../interfaces/ASTNode"; +import { TypeScriptProperties } from "./properties"; +/** + * A class that visits ASTNodes from a TypeScript tree. + */ +export declare class TypeScriptVisitor extends Visitor { + private ast; + private source; + constructor(source: Source, options: Partial); + /** + * Determines whether a node has inheritance + */ + private hasInheritance; + /** + * Returns a node's inheritance type + */ + private getInheritanceType; + /** + * Determines whether an export is default + */ + private hasDefaultExport; + /** + * Returns only the comments from a node's children. + */ + private filterType; + getAST(): ASTNode[]; + visitNode: (node: SyntaxNode, properties?: Partial) => ASTNode; + visitChildren: (nodes: SyntaxNode[]) => ASTNode[]; + private visitProgram; + private visitComment; + /** + * Visit the contextual node + * + * # Remark + * + * A node is considered contextual when a comment is visited and the node is its sibling. + */ + private visitContext; + private visitExportStatement; + private visitExpressionStatement; + private visitInternalModule; + private visitClassOrInterface; + private visitNonTerminal; + private visitTerminal; +} diff --git a/build/src/lang/typescript/visitor.js b/build/src/lang/typescript/visitor.js new file mode 100644 index 0000000..945893f --- /dev/null +++ b/build/src/lang/typescript/visitor.js @@ -0,0 +1,283 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const comment_1 = require("../../utils/comment"); +const sibling_1 = require("../../utils/sibling"); +const _ = require("lodash"); +const log_1 = require("../../utils/log"); +const match_1 = require("../../utils/match"); +const visitor_1 = require("../common/visitor"); +const ast_1 = require("../common/ast"); +/** + * A class that visits ASTNodes from a TypeScript tree. + */ +class TypeScriptVisitor extends visitor_1.default { + constructor(source, options) { + super(options); + this.ast = []; + /* Visitors */ + this.visitNode = (node, properties) => { + switch (node.type) { + case 'program': + this.ast = this.visitProgram(node); + break; + case 'comment': + return this.visitComment(node); + case 'MISSING': + case 'ERROR': + this.logger.report(this.source, node, log_1.ErrorType.TreeSitterParseError); + break; + default: + /* Match other non-terminals */ + if (match_1.default(node, 'constraint', 'formal_parameters', 'required_parameter', 'rest_parameter', 'type_identifier', 'type_parameters', 'type_parameter', 'type_annotation', 'object_type', 'predefined_type', 'parenthesized_type', 'literal_type', 'intersection_type', 'union_type', 'class_body', 'extends_clause', 'unary_expression', 'binary_expression', 'member_expression', 'statement_block', 'return_statement', 'export_statement', 'expression_statement', + // A call_signature can also be a non-contextual node + 'call_signature', 'internal_module', 'variable_declarator', 'object')) { + return this.visitNonTerminal(node, properties); + } + /* Match terminals */ + if (match_1.default(node, 'identifier', 'extends', 'property_identifier', 'accessibility_modifier', 'string', 'void', 'boolean', 'null', 'undefined', 'number', 'return', 'get', 'function', 'namespace', 'const')) { + return this.visitTerminal(node); + } + this.logger.report(this.source, node, log_1.ErrorType.NodeTypeNotYetSupported); + break; + } + }; + this.visitChildren = (nodes) => { + let children = []; + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + if (!node.type.match(/[<>(){},:;\[\]&|=\+\-\*\/]/) && node.type !== '...') { + const child = this.visitNode(node); + if (child) + children.push(child); + } + } + return children; + }; + this.visitProgram = (node) => { + let visited = {}, getStartLocation = (n) => `${n.location.row.start}:${n.location.column.start}`; + // A program can have modules, namespaces, comments as its children + // The first step is to parse all the comments in the root node + let comments = this.visitChildren(this.filterType(node, 'comment')); + // Parse the namespaces in expression_statement + let namespaces = this.visitChildren(this.filterType(node, 'expression_statement')); + // Parse the export statements in the root node + let exports = this.visitChildren(this.filterType(node, 'export_statement')); + // Get the visited context nodes + for (let i = 0; i < comments.length; i++) { + const comment = comments[i]; + const context = comment; + visited[getStartLocation(context)] = true; + } + // Remove the visited nodes from namespaces array + _.remove(namespaces, x => visited[getStartLocation(x)]); + // Exports are oddballs since some exports may reference + // a type/node that may have been commented. + // We'll first need to filter the ones we have visited + _.remove(exports, x => visited[getStartLocation(x)]); + // From the ones we have not visited, we'll need to modify + // the node properties of each context in a comment node that + // matches the ones we have not visited. + const matched = {}; + comments = _.compact(comments.map(comment => { + for (let i = 0; i < exports.length; i++) { + const export_ = exports[i]; + const context = comment.context; + for (let j = 0; context && j < context.children.length; j++) { + if (context.children[i] && context.children[i].type === export_.type) { + matched[getStartLocation(export_)] = true; + comment.context.properties = Object.assign(comment.context.properties || {}, export_.properties); + } + } + } + return comment; + })); + // Removed the matched exports + _.remove(exports, x => matched[getStartLocation(x)]); + return [].concat(comments).concat(namespaces).concat(exports); + }; + this.visitComment = (node) => { + if (comment_1.isJavaDocComment(this.source, node) && !comment_1.isLegalComment(this.source, node)) { + const nextSibling = sibling_1.sibling(node); + if (nextSibling) { + return ast_1.createASTNode(this.source, node, this.visitContext(nextSibling, {}), true); + } + } + }; + /** + * Visit the contextual node + * + * # Remark + * + * A node is considered contextual when a comment is visited and the node is its sibling. + */ + this.visitContext = (node, properties) => { + switch (node.type) { + case 'export_statement': + return this.visitExportStatement(node, properties); + case 'expression_statement': + return this.visitExpressionStatement(node, properties); + case 'class': + case 'interface_declaration': + return this.visitClassOrInterface(node, properties); + case 'function': + case 'call_signature': + case 'method_signature': + case 'property_signature': + case 'public_field_definition': + case 'method_definition': + case 'lexical_declaration': + return this.visitNonTerminal(node, properties); + default: + this.logger.report(this.source, node, log_1.ErrorType.NodeTypeNotYetSupported); + break; + } + }; + /* Statements */ + this.visitExportStatement = (node, properties) => { + let children = node.children, defaultExport = false; + // Remove 'export' since it's always first in the array + children.shift(); + if (this.hasDefaultExport(node)) { + defaultExport = true; + // Remove 'default' export + children.shift(); + } + const child = children.shift(); + return this.visitNode(child, { exports: { export: true, default: defaultExport } }); + }; + this.visitExpressionStatement = (node, properties) => { + let children = node.children; + const child = children.shift(); + if (match_1.default(child, 'internal_module')) { + return this.visitInternalModule(child, properties); + } + if (match_1.default(child, 'function')) { + if (properties) + return this.visitContext(child, properties); + } + return this.visitNonTerminal(child); + }; + /* Modules */ + this.visitInternalModule = (node, properties) => { + let children = node.children.map(child => { + if (match_1.default(child, 'statement_block')) { + return ast_1.createASTNode(this.source, node, this.visitChildren(this.filterType(child, 'comment'))); + } + return this.visitNode(child); + }); + return ast_1.createASTNode(this.source, node, children, Object.assign(properties || {}, { namespace: true })); + }; + /* Declarations */ + this.visitClassOrInterface = (node, properties) => { + // Since 'interface' or 'class' is always first in the array + // we'll need to remove it from the array. + let children = node.children; + const interface_ = children.shift(); + let extends_ = false, implements_ = false; + if (this.hasInheritance(node)) { + const inheritance = this.getInheritanceType(node); + extends_ = inheritance === 'extends'; + implements_ = inheritance === 'implements'; + } + const node_ = ast_1.createASTNode(this.source, node, this.visitChildren(children), Object.assign(properties || {}, { + inheritance: { + implements: implements_, + extends: extends_ + } + })); + if (match_1.default(node, 'class')) { + return node_; + } + // Overwrite the node type from 'interface_declaration' to 'interface' + return Object.assign(node_, { type: interface_.type }); + }; + /* Non-terminals */ + this.visitNonTerminal = (node, properties) => { + let children = node.children; + // Handle special cases where some non-terminals + // contain comments which is what we care about + if (match_1.default(node, 'class_body', 'object_type')) { + children = this.filterType(node, 'comment'); + } + // Handle special cases where export statements have node properties + if (match_1.default(node, 'export_statement')) { + return this.visitExportStatement(node); + } + // Handle special cases where an internal module contains other nodes + if (match_1.default(node, 'internal_module')) { + return this.visitInternalModule(node, properties); + } + // Handle special cases where an intermal_module can exist in an expression_statement + if (match_1.default(node, 'expression_statement')) { + return this.visitExpressionStatement(node, properties); + } + if (match_1.default(node, 'function') || match_1.default(node, 'method_definition')) { + _.remove(children, child => match_1.default(child, 'statement_block')); + return ast_1.createASTNode(this.source, node, this.visitChildren(children), properties); + } + return ast_1.createASTNode(this.source, node, this.visitChildren(children), properties); + }; + /* Terminals */ + this.visitTerminal = (node) => { + return ast_1.createASTNode(this.source, node); + }; + this.source = source; + } + /** + * Determines whether a node has inheritance + */ + hasInheritance(node) { + let inherits = false; + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match_1.default(child, 'extends', 'implements')) { + inherits = true; + } + } + return inherits; + } + /** + * Returns a node's inheritance type + */ + getInheritanceType(node) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match_1.default(child, 'extends')) { + return 'extends'; + } + if (match_1.default(child, 'implements')) { + return 'implements'; + } + } + } + /** + * Determines whether an export is default + */ + hasDefaultExport(node) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match_1.default(child, 'default')) { + return true; + } + } + return false; + } + /** + * Returns only the comments from a node's children. + */ + filterType(node, type) { + let children = []; + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match_1.default(child, type)) { + children.push(child); + } + } + return children; + } + getAST() { + return this.ast; + } +} +exports.TypeScriptVisitor = TypeScriptVisitor; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlzaXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9sYW5nL3R5cGVzY3JpcHQvdmlzaXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLGlEQUF1RTtBQUN2RSxpREFBOEM7QUFFOUMsNEJBQTRCO0FBQzVCLHlDQUFpRDtBQUNqRCw2Q0FBc0M7QUFFdEMsK0NBQTREO0FBRTVELHVDQUE4QztBQUc5Qzs7R0FFRztBQUNILE1BQWEsaUJBQWtCLFNBQVEsaUJBQU87SUFHNUMsWUFBWSxNQUFjLEVBQUUsT0FBZ0M7UUFDMUQsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBSFIsUUFBRyxHQUFjLEVBQUUsQ0FBQTtRQW9FM0IsZUFBZTtRQUVmLGNBQVMsR0FBRyxDQUNWLElBQWdCLEVBQ2hCLFVBQTBDLEVBQzFDLEVBQUU7WUFDRixRQUFRLElBQUksQ0FBQyxJQUFJLEVBQUU7Z0JBQ2pCLEtBQUssU0FBUztvQkFDWixJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUM7b0JBQ25DLE1BQU07Z0JBQ1IsS0FBSyxTQUFTO29CQUNaLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDakMsS0FBSyxTQUFTLENBQUM7Z0JBQ2YsS0FBSyxPQUFPO29CQUNWLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLGVBQVMsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO29CQUN0RSxNQUFNO2dCQUNSO29CQUVFLCtCQUErQjtvQkFFL0IsSUFBSSxlQUFLLENBQUMsSUFBSSxFQUNaLFlBQVksRUFDWixtQkFBbUIsRUFBRSxvQkFBb0IsRUFBRSxnQkFBZ0IsRUFDM0QsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQUUsZ0JBQWdCLEVBQUUsaUJBQWlCLEVBQ3pFLGFBQWEsRUFBRSxpQkFBaUIsRUFBRSxvQkFBb0IsRUFBRSxjQUFjLEVBQ3RFLG1CQUFtQixFQUFFLFlBQVksRUFDakMsWUFBWSxFQUNaLGdCQUFnQixFQUNoQixrQkFBa0IsRUFBRSxtQkFBbUIsRUFBRSxtQkFBbUIsRUFDNUQsaUJBQWlCLEVBQUUsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQUUsc0JBQXNCO29CQUNqRixxREFBcUQ7b0JBQ3JELGdCQUFnQixFQUNoQixpQkFBaUIsRUFDakIscUJBQXFCLEVBQ3JCLFFBQVEsQ0FDVCxFQUFFO3dCQUNELE9BQU8sSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQTtxQkFDL0M7b0JBRUQscUJBQXFCO29CQUNyQixJQUFJLGVBQUssQ0FBQyxJQUFJLEVBQ1osWUFBWSxFQUFFLFNBQVMsRUFBRSxxQkFBcUIsRUFBRSx3QkFBd0IsRUFDeEUsUUFBUSxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUNwRSxLQUFLLEVBQUUsVUFBVSxFQUFFLFdBQVcsRUFBRSxPQUFPLENBQ3hDLEVBQUU7d0JBQ0QsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO3FCQUNqQztvQkFDRCxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxlQUFTLENBQUMsdUJBQXVCLENBQUMsQ0FBQztvQkFDekUsTUFBTTthQUNUO1FBQ0gsQ0FBQyxDQUFBO1FBRUQsa0JBQWEsR0FBRyxDQUFDLEtBQW1CLEVBQWEsRUFBRTtZQUNqRCxJQUFJLFFBQVEsR0FBYyxFQUFFLENBQUM7WUFDN0IsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7Z0JBQ3JDLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDdEIsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLDRCQUE0QixDQUFDLElBQUksSUFBSSxDQUFDLElBQUksS0FBSyxLQUFLLEVBQUU7b0JBQ3pFLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7b0JBQ25DLElBQUksS0FBSzt3QkFBRSxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO2lCQUNqQzthQUNGO1lBQ0QsT0FBTyxRQUFRLENBQUM7UUFDbEIsQ0FBQyxDQUFBO1FBRU8saUJBQVksR0FBRyxDQUFDLElBQWdCLEVBQWEsRUFBRTtZQUNyRCxJQUFJLE9BQU8sR0FBRyxFQUFFLEVBQ2QsZ0JBQWdCLEdBQUcsQ0FBQyxDQUFVLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQzFGLG1FQUFtRTtZQUNuRSwrREFBK0Q7WUFDL0QsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDO1lBQ3BFLCtDQUErQztZQUMvQyxJQUFJLFVBQVUsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLHNCQUFzQixDQUFDLENBQUMsQ0FBQztZQUNuRiwrQ0FBK0M7WUFDL0MsSUFBSSxPQUFPLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxrQkFBa0IsQ0FBQyxDQUFDLENBQUM7WUFFNUUsZ0NBQWdDO1lBQ2hDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO2dCQUN4QyxNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQzVCLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQztnQkFDeEIsT0FBTyxDQUFDLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDO2FBQzNDO1lBRUQsaURBQWlEO1lBQ2pELENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUV4RCx3REFBd0Q7WUFDeEQsNENBQTRDO1lBQzVDLHNEQUFzRDtZQUN0RCxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFFckQsMERBQTBEO1lBQzFELDZEQUE2RDtZQUM3RCx3Q0FBd0M7WUFDeEMsTUFBTSxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ25CLFFBQVEsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUNsQixRQUFRLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxFQUFFO2dCQUNyQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtvQkFDdkMsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUMzQixNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDO29CQUNoQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxPQUFPLElBQUksQ0FBQyxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO3dCQUMzRCxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssT0FBTyxDQUFDLElBQUksRUFBRTs0QkFDcEUsT0FBTyxDQUFDLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDOzRCQUMxQyxPQUFPLENBQUMsT0FBTyxDQUFDLFVBQVUsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUN4QyxPQUFPLENBQUMsT0FBTyxDQUFDLFVBQVUsSUFBSSxFQUFFLEVBQ2hDLE9BQU8sQ0FBQyxVQUFVLENBQ25CLENBQUM7eUJBQ0g7cUJBQ0Y7aUJBQ0Y7Z0JBQ0QsT0FBTyxPQUFPLENBQUM7WUFDakIsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUVOLDhCQUE4QjtZQUM5QixDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7WUFFcEQsT0FBTyxFQUFFLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDaEUsQ0FBQyxDQUFBO1FBRU8saUJBQVksR0FBRyxDQUFDLElBQWdCLEVBQVcsRUFBRTtZQUNuRCxJQUFJLDBCQUFnQixDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyx3QkFBYyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUU7Z0JBQzdFLE1BQU0sV0FBVyxHQUFHLGlCQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ2xDLElBQUksV0FBVyxFQUFFO29CQUNmLE9BQU8sbUJBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQTtpQkFDbEY7YUFDRjtRQUNILENBQUMsQ0FBQTtRQUVEOzs7Ozs7V0FNRztRQUNLLGlCQUFZLEdBQUcsQ0FBQyxJQUFnQixFQUFFLFVBQTBDLEVBQVcsRUFBRTtZQUMvRixRQUFRLElBQUksQ0FBQyxJQUFJLEVBQUU7Z0JBQ2pCLEtBQUssa0JBQWtCO29CQUNyQixPQUFPLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUM7Z0JBQ3JELEtBQUssc0JBQXNCO29CQUN6QixPQUFPLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUM7Z0JBQ3pELEtBQUssT0FBTyxDQUFDO2dCQUNiLEtBQUssdUJBQXVCO29CQUMxQixPQUFPLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUE7Z0JBQ3JELEtBQUssVUFBVSxDQUFDO2dCQUNoQixLQUFLLGdCQUFnQixDQUFDO2dCQUN0QixLQUFLLGtCQUFrQixDQUFDO2dCQUN4QixLQUFLLG9CQUFvQixDQUFDO2dCQUMxQixLQUFLLHlCQUF5QixDQUFDO2dCQUMvQixLQUFLLG1CQUFtQixDQUFDO2dCQUN6QixLQUFLLHFCQUFxQjtvQkFDeEIsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDO2dCQUNqRDtvQkFDRSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxlQUFTLENBQUMsdUJBQXVCLENBQUMsQ0FBQztvQkFDekUsTUFBTTthQUNUO1FBQ0gsQ0FBQyxDQUFBO1FBRUQsZ0JBQWdCO1FBRVIseUJBQW9CLEdBQUcsQ0FBQyxJQUFnQixFQUFFLFVBQTBDLEVBQVcsRUFBRTtZQUN2RyxJQUFJLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUSxFQUFFLGFBQWEsR0FBRyxLQUFLLENBQUM7WUFDcEQsdURBQXVEO1lBQ3ZELFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNqQixJQUFJLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsRUFBRTtnQkFDL0IsYUFBYSxHQUFHLElBQUksQ0FBQztnQkFDckIsMEJBQTBCO2dCQUMxQixRQUFRLENBQUMsS0FBSyxFQUFFLENBQUM7YUFDbEI7WUFDRCxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDL0IsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxFQUFFLE9BQU8sRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLGFBQWEsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUN0RixDQUFDLENBQUE7UUFFTyw2QkFBd0IsR0FBRyxDQUFDLElBQWdCLEVBQUUsVUFBeUMsRUFBVyxFQUFFO1lBQzFHLElBQUksUUFBUSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7WUFDN0IsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBRS9CLElBQUksZUFBSyxDQUFDLEtBQUssRUFBRSxpQkFBaUIsQ0FBQyxFQUFFO2dCQUNuQyxPQUFPLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLEVBQUUsVUFBVSxDQUFDLENBQUE7YUFDbkQ7WUFFRCxJQUFJLGVBQUssQ0FBQyxLQUFLLEVBQUUsVUFBVSxDQUFDLEVBQUU7Z0JBQzVCLElBQUksVUFBVTtvQkFBRSxPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFLFVBQVUsQ0FBQyxDQUFDO2FBQzdEO1lBRUQsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDckMsQ0FBQyxDQUFBO1FBRUQsYUFBYTtRQUVMLHdCQUFtQixHQUFHLENBQUMsSUFBZ0IsRUFBRSxVQUEwQyxFQUFXLEVBQUU7WUFDdEcsSUFBSSxRQUFRLEdBQWMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUU7Z0JBQ2xELElBQUksZUFBSyxDQUFDLEtBQUssRUFBRSxpQkFBaUIsQ0FBQyxFQUFFO29CQUNuQyxPQUFPLG1CQUFhLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUE7aUJBQy9GO2dCQUNELE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUMvQixDQUFDLENBQUMsQ0FBQztZQUNILE9BQU8sbUJBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxVQUFVLElBQUksRUFBRSxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztRQUMxRyxDQUFDLENBQUE7UUFHRCxrQkFBa0I7UUFFViwwQkFBcUIsR0FBRyxDQUFDLElBQWdCLEVBQUUsVUFBMEMsRUFBVyxFQUFFO1lBQ3hHLDREQUE0RDtZQUM1RCwwQ0FBMEM7WUFDMUMsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQztZQUM3QixNQUFNLFVBQVUsR0FBRyxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDcEMsSUFBSSxRQUFRLEdBQUcsS0FBSyxFQUFFLFdBQVcsR0FBRyxLQUFLLENBQUM7WUFDMUMsSUFBSSxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxFQUFFO2dCQUM3QixNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLENBQUE7Z0JBQ2pELFFBQVEsR0FBRyxXQUFXLEtBQUssU0FBUyxDQUFDO2dCQUNyQyxXQUFXLEdBQUcsV0FBVyxLQUFLLFlBQVksQ0FBQzthQUM1QztZQUVELE1BQU0sS0FBSyxHQUFHLG1CQUFhLENBQ3pCLElBQUksQ0FBQyxNQUFNLEVBQ1gsSUFBSSxFQUNKLElBQUksQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLEVBQzVCLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBVSxJQUFJLEVBQUUsRUFBRTtnQkFDOUIsV0FBVyxFQUFFO29CQUNYLFVBQVUsRUFBRSxXQUFXO29CQUN2QixPQUFPLEVBQUUsUUFBUTtpQkFDTzthQUMzQixDQUFDLENBQUMsQ0FBQztZQUVOLElBQUksZUFBSyxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsRUFBRTtnQkFDeEIsT0FBTyxLQUFLLENBQUM7YUFDZDtZQUNELHNFQUFzRTtZQUN0RSxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFBO1FBQ3hELENBQUMsQ0FBQTtRQUVELG1CQUFtQjtRQUVYLHFCQUFnQixHQUFHLENBQUMsSUFBZ0IsRUFBRSxVQUEwQyxFQUFXLEVBQUU7WUFDbkcsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQztZQUM3QixnREFBZ0Q7WUFDaEQsK0NBQStDO1lBQy9DLElBQUksZUFBSyxDQUFDLElBQUksRUFBRSxZQUFZLEVBQUUsYUFBYSxDQUFDLEVBQUU7Z0JBQzVDLFFBQVEsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQzthQUM3QztZQUNELG9FQUFvRTtZQUNwRSxJQUFJLGVBQUssQ0FBQyxJQUFJLEVBQUUsa0JBQWtCLENBQUMsRUFBRTtnQkFDbkMsT0FBTyxJQUFJLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDeEM7WUFFRCxxRUFBcUU7WUFDckUsSUFBSSxlQUFLLENBQUMsSUFBSSxFQUFFLGlCQUFpQixDQUFDLEVBQUU7Z0JBQ2xDLE9BQU8sSUFBSSxDQUFDLG1CQUFtQixDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQzthQUNuRDtZQUVELHFGQUFxRjtZQUNyRixJQUFJLGVBQUssQ0FBQyxJQUFJLEVBQUUsc0JBQXNCLENBQUMsRUFBRTtnQkFDdkMsT0FBTyxJQUFJLENBQUMsd0JBQXdCLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDO2FBQ3hEO1lBRUQsSUFBSSxlQUFLLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxJQUFJLGVBQUssQ0FBQyxJQUFJLEVBQUUsbUJBQW1CLENBQUMsRUFBRTtnQkFDL0QsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxlQUFLLENBQUMsS0FBSyxFQUFFLGlCQUFpQixDQUFDLENBQUMsQ0FBQTtnQkFDNUQsT0FBTyxtQkFBYSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLEVBQUUsVUFBVSxDQUFDLENBQUM7YUFDbkY7WUFFRCxPQUFPLG1CQUFhLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQztRQUNwRixDQUFDLENBQUE7UUFFRCxlQUFlO1FBRVAsa0JBQWEsR0FBRyxDQUFDLElBQWdCLEVBQVcsRUFBRTtZQUNwRCxPQUFPLG1CQUFhLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsQ0FBQTtRQUN6QyxDQUFDLENBQUE7UUE1VUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7SUFDdkIsQ0FBQztJQUVEOztPQUVHO0lBQ0ssY0FBYyxDQUFDLElBQWdCO1FBQ3JDLElBQUksUUFBUSxHQUFHLEtBQUssQ0FBQztRQUNyQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDN0MsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMvQixJQUFJLGVBQUssQ0FBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLFlBQVksQ0FBQyxFQUFFO2dCQUN6QyxRQUFRLEdBQUcsSUFBSSxDQUFDO2FBQ2pCO1NBQ0Y7UUFDRCxPQUFPLFFBQVEsQ0FBQTtJQUNqQixDQUFDO0lBRUQ7O09BRUc7SUFDSyxrQkFBa0IsQ0FBQyxJQUFnQjtRQUN6QyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDN0MsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMvQixJQUFJLGVBQUssQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLEVBQUU7Z0JBQzNCLE9BQU8sU0FBUyxDQUFDO2FBQ2xCO1lBRUQsSUFBSSxlQUFLLENBQUMsS0FBSyxFQUFFLFlBQVksQ0FBQyxFQUFFO2dCQUM5QixPQUFPLFlBQVksQ0FBQzthQUNyQjtTQUNGO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssZ0JBQWdCLENBQUMsSUFBZ0I7UUFDdkMsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQzdDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDL0IsSUFBSSxlQUFLLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQyxFQUFFO2dCQUMzQixPQUFPLElBQUksQ0FBQzthQUNiO1NBQ0Y7UUFDRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRDs7T0FFRztJQUNLLFVBQVUsQ0FBQyxJQUFnQixFQUFFLElBQVk7UUFDL0MsSUFBSSxRQUFRLEdBQWlCLEVBQUUsQ0FBQztRQUNoQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDN0MsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMvQixJQUFJLGVBQUssQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLEVBQUU7Z0JBQ3RCLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7YUFDdEI7U0FDRjtRQUNELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7SUFFRCxNQUFNO1FBQ0osT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDO0lBQ2xCLENBQUM7Q0ErUUY7QUFsVkQsOENBa1ZDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaXNKYXZhRG9jQ29tbWVudCwgaXNMZWdhbENvbW1lbnQgfSBmcm9tIFwiLi4vLi4vdXRpbHMvY29tbWVudFwiO1xuaW1wb3J0IHsgc2libGluZyB9IGZyb20gXCIuLi8uLi91dGlscy9zaWJsaW5nXCI7XG5pbXBvcnQgeyBTeW50YXhOb2RlIH0gZnJvbSBcInRyZWUtc2l0dGVyXCI7XG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgbG9nLCB7IEVycm9yVHlwZSB9IGZyb20gXCIuLi8uLi91dGlscy9sb2dcIjtcbmltcG9ydCBtYXRjaCBmcm9tIFwiLi4vLi4vdXRpbHMvbWF0Y2hcIjtcbmltcG9ydCBTb3VyY2UgZnJvbSBcIi4uLy4uL2ludGVyZmFjZXMvU291cmNlXCI7XG5pbXBvcnQgVmlzaXRvciwgeyBWaXNpdG9yT3B0aW9ucyB9IGZyb20gXCIuLi9jb21tb24vdmlzaXRvclwiO1xuaW1wb3J0IEFTVE5vZGUgZnJvbSBcIi4uLy4uL2ludGVyZmFjZXMvQVNUTm9kZVwiO1xuaW1wb3J0IHsgY3JlYXRlQVNUTm9kZSB9IGZyb20gXCIuLi9jb21tb24vYXN0XCI7XG5pbXBvcnQgeyBUeXBlU2NyaXB0UHJvcGVydGllcywgVHlwZVNjcmlwdEluaGVyaXRhbmNlIH0gZnJvbSBcIi4vcHJvcGVydGllc1wiO1xuXG4vKipcbiAqIEEgY2xhc3MgdGhhdCB2aXNpdHMgQVNUTm9kZXMgZnJvbSBhIFR5cGVTY3JpcHQgdHJlZS5cbiAqL1xuZXhwb3J0IGNsYXNzIFR5cGVTY3JpcHRWaXNpdG9yIGV4dGVuZHMgVmlzaXRvciB7XG4gIHByaXZhdGUgYXN0OiBBU1ROb2RlW10gPSBbXVxuICBwcml2YXRlIHNvdXJjZTogU291cmNlXG4gIGNvbnN0cnVjdG9yKHNvdXJjZTogU291cmNlLCBvcHRpb25zOiBQYXJ0aWFsPFZpc2l0b3JPcHRpb25zPikge1xuICAgIHN1cGVyKG9wdGlvbnMpXG4gICAgdGhpcy5zb3VyY2UgPSBzb3VyY2U7XG4gIH1cblxuICAvKipcbiAgICogRGV0ZXJtaW5lcyB3aGV0aGVyIGEgbm9kZSBoYXMgaW5oZXJpdGFuY2VcbiAgICovXG4gIHByaXZhdGUgaGFzSW5oZXJpdGFuY2Uobm9kZTogU3ludGF4Tm9kZSkge1xuICAgIGxldCBpbmhlcml0cyA9IGZhbHNlO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbm9kZS5jaGlsZHJlbi5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgY2hpbGQgPSBub2RlLmNoaWxkcmVuW2ldO1xuICAgICAgaWYgKG1hdGNoKGNoaWxkLCAnZXh0ZW5kcycsICdpbXBsZW1lbnRzJykpIHtcbiAgICAgICAgaW5oZXJpdHMgPSB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gaW5oZXJpdHNcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgbm9kZSdzIGluaGVyaXRhbmNlIHR5cGVcbiAgICovXG4gIHByaXZhdGUgZ2V0SW5oZXJpdGFuY2VUeXBlKG5vZGU6IFN5bnRheE5vZGUpIHtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5vZGUuY2hpbGRyZW4ubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGNoaWxkID0gbm9kZS5jaGlsZHJlbltpXTtcbiAgICAgIGlmIChtYXRjaChjaGlsZCwgJ2V4dGVuZHMnKSkge1xuICAgICAgICByZXR1cm4gJ2V4dGVuZHMnO1xuICAgICAgfVxuXG4gICAgICBpZiAobWF0Y2goY2hpbGQsICdpbXBsZW1lbnRzJykpIHtcbiAgICAgICAgcmV0dXJuICdpbXBsZW1lbnRzJztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRGV0ZXJtaW5lcyB3aGV0aGVyIGFuIGV4cG9ydCBpcyBkZWZhdWx0XG4gICAqL1xuICBwcml2YXRlIGhhc0RlZmF1bHRFeHBvcnQobm9kZTogU3ludGF4Tm9kZSk6IGJvb2xlYW4ge1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbm9kZS5jaGlsZHJlbi5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgY2hpbGQgPSBub2RlLmNoaWxkcmVuW2ldO1xuICAgICAgaWYgKG1hdGNoKGNoaWxkLCAnZGVmYXVsdCcpKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBvbmx5IHRoZSBjb21tZW50cyBmcm9tIGEgbm9kZSdzIGNoaWxkcmVuLlxuICAgKi9cbiAgcHJpdmF0ZSBmaWx0ZXJUeXBlKG5vZGU6IFN5bnRheE5vZGUsIHR5cGU6IHN0cmluZyk6IFN5bnRheE5vZGVbXSB7XG4gICAgbGV0IGNoaWxkcmVuOiBTeW50YXhOb2RlW10gPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5vZGUuY2hpbGRyZW4ubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGNoaWxkID0gbm9kZS5jaGlsZHJlbltpXTtcbiAgICAgIGlmIChtYXRjaChjaGlsZCwgdHlwZSkpIHtcbiAgICAgICAgY2hpbGRyZW4ucHVzaChjaGlsZCk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjaGlsZHJlbjtcbiAgfVxuXG4gIGdldEFTVCgpOiBBU1ROb2RlW10ge1xuICAgIHJldHVybiB0aGlzLmFzdDtcbiAgfVxuXG4gIC8qIFZpc2l0b3JzICAqL1xuXG4gIHZpc2l0Tm9kZSA9IChcbiAgICBub2RlOiBTeW50YXhOb2RlLFxuICAgIHByb3BlcnRpZXM/OiBQYXJ0aWFsPFR5cGVTY3JpcHRQcm9wZXJ0aWVzPlxuICApID0+IHtcbiAgICBzd2l0Y2ggKG5vZGUudHlwZSkge1xuICAgICAgY2FzZSAncHJvZ3JhbSc6XG4gICAgICAgIHRoaXMuYXN0ID0gdGhpcy52aXNpdFByb2dyYW0obm9kZSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnY29tbWVudCc6XG4gICAgICAgIHJldHVybiB0aGlzLnZpc2l0Q29tbWVudChub2RlKTtcbiAgICAgIGNhc2UgJ01JU1NJTkcnOlxuICAgICAgY2FzZSAnRVJST1InOlxuICAgICAgICB0aGlzLmxvZ2dlci5yZXBvcnQodGhpcy5zb3VyY2UsIG5vZGUsIEVycm9yVHlwZS5UcmVlU2l0dGVyUGFyc2VFcnJvcik7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcblxuICAgICAgICAvKiBNYXRjaCBvdGhlciBub24tdGVybWluYWxzICovXG5cbiAgICAgICAgaWYgKG1hdGNoKG5vZGUsXG4gICAgICAgICAgJ2NvbnN0cmFpbnQnLFxuICAgICAgICAgICdmb3JtYWxfcGFyYW1ldGVycycsICdyZXF1aXJlZF9wYXJhbWV0ZXInLCAncmVzdF9wYXJhbWV0ZXInLFxuICAgICAgICAgICd0eXBlX2lkZW50aWZpZXInLCAndHlwZV9wYXJhbWV0ZXJzJywgJ3R5cGVfcGFyYW1ldGVyJywgJ3R5cGVfYW5ub3RhdGlvbicsXG4gICAgICAgICAgJ29iamVjdF90eXBlJywgJ3ByZWRlZmluZWRfdHlwZScsICdwYXJlbnRoZXNpemVkX3R5cGUnLCAnbGl0ZXJhbF90eXBlJyxcbiAgICAgICAgICAnaW50ZXJzZWN0aW9uX3R5cGUnLCAndW5pb25fdHlwZScsXG4gICAgICAgICAgJ2NsYXNzX2JvZHknLFxuICAgICAgICAgICdleHRlbmRzX2NsYXVzZScsXG4gICAgICAgICAgJ3VuYXJ5X2V4cHJlc3Npb24nLCAnYmluYXJ5X2V4cHJlc3Npb24nLCAnbWVtYmVyX2V4cHJlc3Npb24nLFxuICAgICAgICAgICdzdGF0ZW1lbnRfYmxvY2snLCAncmV0dXJuX3N0YXRlbWVudCcsICdleHBvcnRfc3RhdGVtZW50JywgJ2V4cHJlc3Npb25fc3RhdGVtZW50JyxcbiAgICAgICAgICAvLyBBIGNhbGxfc2lnbmF0dXJlIGNhbiBhbHNvIGJlIGEgbm9uLWNvbnRleHR1YWwgbm9kZVxuICAgICAgICAgICdjYWxsX3NpZ25hdHVyZScsXG4gICAgICAgICAgJ2ludGVybmFsX21vZHVsZScsXG4gICAgICAgICAgJ3ZhcmlhYmxlX2RlY2xhcmF0b3InLFxuICAgICAgICAgICdvYmplY3QnXG4gICAgICAgICkpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy52aXNpdE5vblRlcm1pbmFsKG5vZGUsIHByb3BlcnRpZXMpXG4gICAgICAgIH1cblxuICAgICAgICAvKiBNYXRjaCB0ZXJtaW5hbHMgKi9cbiAgICAgICAgaWYgKG1hdGNoKG5vZGUsXG4gICAgICAgICAgJ2lkZW50aWZpZXInLCAnZXh0ZW5kcycsICdwcm9wZXJ0eV9pZGVudGlmaWVyJywgJ2FjY2Vzc2liaWxpdHlfbW9kaWZpZXInLFxuICAgICAgICAgICdzdHJpbmcnLCAndm9pZCcsICdib29sZWFuJywgJ251bGwnLCAndW5kZWZpbmVkJywgJ251bWJlcicsICdyZXR1cm4nLFxuICAgICAgICAgICdnZXQnLCAnZnVuY3Rpb24nLCAnbmFtZXNwYWNlJywgJ2NvbnN0J1xuICAgICAgICApKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMudmlzaXRUZXJtaW5hbChub2RlKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmxvZ2dlci5yZXBvcnQodGhpcy5zb3VyY2UsIG5vZGUsIEVycm9yVHlwZS5Ob2RlVHlwZU5vdFlldFN1cHBvcnRlZCk7XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIHZpc2l0Q2hpbGRyZW4gPSAobm9kZXM6IFN5bnRheE5vZGVbXSk6IEFTVE5vZGVbXSA9PiB7XG4gICAgbGV0IGNoaWxkcmVuOiBBU1ROb2RlW10gPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBub2RlID0gbm9kZXNbaV07XG4gICAgICBpZiAoIW5vZGUudHlwZS5tYXRjaCgvWzw+KCl7fSw6O1xcW1xcXSZ8PVxcK1xcLVxcKlxcL10vKSAmJiBub2RlLnR5cGUgIT09ICcuLi4nKSB7XG4gICAgICAgIGNvbnN0IGNoaWxkID0gdGhpcy52aXNpdE5vZGUobm9kZSk7XG4gICAgICAgIGlmIChjaGlsZCkgY2hpbGRyZW4ucHVzaChjaGlsZCk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjaGlsZHJlbjtcbiAgfVxuXG4gIHByaXZhdGUgdmlzaXRQcm9ncmFtID0gKG5vZGU6IFN5bnRheE5vZGUpOiBBU1ROb2RlW10gPT4ge1xuICAgIGxldCB2aXNpdGVkID0ge30sXG4gICAgICBnZXRTdGFydExvY2F0aW9uID0gKG46IEFTVE5vZGUpID0+IGAke24ubG9jYXRpb24ucm93LnN0YXJ0fToke24ubG9jYXRpb24uY29sdW1uLnN0YXJ0fWA7XG4gICAgLy8gQSBwcm9ncmFtIGNhbiBoYXZlIG1vZHVsZXMsIG5hbWVzcGFjZXMsIGNvbW1lbnRzIGFzIGl0cyBjaGlsZHJlblxuICAgIC8vIFRoZSBmaXJzdCBzdGVwIGlzIHRvIHBhcnNlIGFsbCB0aGUgY29tbWVudHMgaW4gdGhlIHJvb3Qgbm9kZVxuICAgIGxldCBjb21tZW50cyA9IHRoaXMudmlzaXRDaGlsZHJlbih0aGlzLmZpbHRlclR5cGUobm9kZSwgJ2NvbW1lbnQnKSk7XG4gICAgLy8gUGFyc2UgdGhlIG5hbWVzcGFjZXMgaW4gZXhwcmVzc2lvbl9zdGF0ZW1lbnRcbiAgICBsZXQgbmFtZXNwYWNlcyA9IHRoaXMudmlzaXRDaGlsZHJlbih0aGlzLmZpbHRlclR5cGUobm9kZSwgJ2V4cHJlc3Npb25fc3RhdGVtZW50JykpO1xuICAgIC8vIFBhcnNlIHRoZSBleHBvcnQgc3RhdGVtZW50cyBpbiB0aGUgcm9vdCBub2RlXG4gICAgbGV0IGV4cG9ydHMgPSB0aGlzLnZpc2l0Q2hpbGRyZW4odGhpcy5maWx0ZXJUeXBlKG5vZGUsICdleHBvcnRfc3RhdGVtZW50JykpO1xuXG4gICAgLy8gR2V0IHRoZSB2aXNpdGVkIGNvbnRleHQgbm9kZXNcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNvbW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBjb21tZW50ID0gY29tbWVudHNbaV07XG4gICAgICBjb25zdCBjb250ZXh0ID0gY29tbWVudDtcbiAgICAgIHZpc2l0ZWRbZ2V0U3RhcnRMb2NhdGlvbihjb250ZXh0KV0gPSB0cnVlO1xuICAgIH1cblxuICAgIC8vIFJlbW92ZSB0aGUgdmlzaXRlZCBub2RlcyBmcm9tIG5hbWVzcGFjZXMgYXJyYXlcbiAgICBfLnJlbW92ZShuYW1lc3BhY2VzLCB4ID0+IHZpc2l0ZWRbZ2V0U3RhcnRMb2NhdGlvbih4KV0pO1xuXG4gICAgLy8gRXhwb3J0cyBhcmUgb2RkYmFsbHMgc2luY2Ugc29tZSBleHBvcnRzIG1heSByZWZlcmVuY2VcbiAgICAvLyBhIHR5cGUvbm9kZSB0aGF0IG1heSBoYXZlIGJlZW4gY29tbWVudGVkLlxuICAgIC8vIFdlJ2xsIGZpcnN0IG5lZWQgdG8gZmlsdGVyIHRoZSBvbmVzIHdlIGhhdmUgdmlzaXRlZFxuICAgIF8ucmVtb3ZlKGV4cG9ydHMsIHggPT4gdmlzaXRlZFtnZXRTdGFydExvY2F0aW9uKHgpXSk7XG5cbiAgICAvLyBGcm9tIHRoZSBvbmVzIHdlIGhhdmUgbm90IHZpc2l0ZWQsIHdlJ2xsIG5lZWQgdG8gbW9kaWZ5XG4gICAgLy8gdGhlIG5vZGUgcHJvcGVydGllcyBvZiBlYWNoIGNvbnRleHQgaW4gYSBjb21tZW50IG5vZGUgdGhhdFxuICAgIC8vIG1hdGNoZXMgdGhlIG9uZXMgd2UgaGF2ZSBub3QgdmlzaXRlZC5cbiAgICBjb25zdCBtYXRjaGVkID0ge307XG4gICAgY29tbWVudHMgPSBfLmNvbXBhY3QoXG4gICAgICBjb21tZW50cy5tYXAoY29tbWVudCA9PiB7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZXhwb3J0cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIGNvbnN0IGV4cG9ydF8gPSBleHBvcnRzW2ldO1xuICAgICAgICAgIGNvbnN0IGNvbnRleHQgPSBjb21tZW50LmNvbnRleHQ7XG4gICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGNvbnRleHQgJiYgaiA8IGNvbnRleHQuY2hpbGRyZW4ubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgIGlmIChjb250ZXh0LmNoaWxkcmVuW2ldICYmIGNvbnRleHQuY2hpbGRyZW5baV0udHlwZSA9PT0gZXhwb3J0Xy50eXBlKSB7XG4gICAgICAgICAgICAgIG1hdGNoZWRbZ2V0U3RhcnRMb2NhdGlvbihleHBvcnRfKV0gPSB0cnVlO1xuICAgICAgICAgICAgICBjb21tZW50LmNvbnRleHQucHJvcGVydGllcyA9IE9iamVjdC5hc3NpZ24oXG4gICAgICAgICAgICAgICAgY29tbWVudC5jb250ZXh0LnByb3BlcnRpZXMgfHwge30sXG4gICAgICAgICAgICAgICAgZXhwb3J0Xy5wcm9wZXJ0aWVzXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBjb21tZW50O1xuICAgICAgfSkpO1xuXG4gICAgLy8gUmVtb3ZlZCB0aGUgbWF0Y2hlZCBleHBvcnRzXG4gICAgXy5yZW1vdmUoZXhwb3J0cywgeCA9PiBtYXRjaGVkW2dldFN0YXJ0TG9jYXRpb24oeCldKVxuXG4gICAgcmV0dXJuIFtdLmNvbmNhdChjb21tZW50cykuY29uY2F0KG5hbWVzcGFjZXMpLmNvbmNhdChleHBvcnRzKTtcbiAgfVxuXG4gIHByaXZhdGUgdmlzaXRDb21tZW50ID0gKG5vZGU6IFN5bnRheE5vZGUpOiBBU1ROb2RlID0+IHtcbiAgICBpZiAoaXNKYXZhRG9jQ29tbWVudCh0aGlzLnNvdXJjZSwgbm9kZSkgJiYgIWlzTGVnYWxDb21tZW50KHRoaXMuc291cmNlLCBub2RlKSkge1xuICAgICAgY29uc3QgbmV4dFNpYmxpbmcgPSBzaWJsaW5nKG5vZGUpO1xuICAgICAgaWYgKG5leHRTaWJsaW5nKSB7XG4gICAgICAgIHJldHVybiBjcmVhdGVBU1ROb2RlKHRoaXMuc291cmNlLCBub2RlLCB0aGlzLnZpc2l0Q29udGV4dChuZXh0U2libGluZywge30pLCB0cnVlKVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBWaXNpdCB0aGUgY29udGV4dHVhbCBub2RlXG4gICAqIFxuICAgKiAjIFJlbWFya1xuICAgKiBcbiAgICogQSBub2RlIGlzIGNvbnNpZGVyZWQgY29udGV4dHVhbCB3aGVuIGEgY29tbWVudCBpcyB2aXNpdGVkIGFuZCB0aGUgbm9kZSBpcyBpdHMgc2libGluZy5cbiAgICovXG4gIHByaXZhdGUgdmlzaXRDb250ZXh0ID0gKG5vZGU6IFN5bnRheE5vZGUsIHByb3BlcnRpZXM/OiBQYXJ0aWFsPFR5cGVTY3JpcHRQcm9wZXJ0aWVzPik6IEFTVE5vZGUgPT4ge1xuICAgIHN3aXRjaCAobm9kZS50eXBlKSB7XG4gICAgICBjYXNlICdleHBvcnRfc3RhdGVtZW50JzpcbiAgICAgICAgcmV0dXJuIHRoaXMudmlzaXRFeHBvcnRTdGF0ZW1lbnQobm9kZSwgcHJvcGVydGllcyk7XG4gICAgICBjYXNlICdleHByZXNzaW9uX3N0YXRlbWVudCc6XG4gICAgICAgIHJldHVybiB0aGlzLnZpc2l0RXhwcmVzc2lvblN0YXRlbWVudChub2RlLCBwcm9wZXJ0aWVzKTtcbiAgICAgIGNhc2UgJ2NsYXNzJzpcbiAgICAgIGNhc2UgJ2ludGVyZmFjZV9kZWNsYXJhdGlvbic6XG4gICAgICAgIHJldHVybiB0aGlzLnZpc2l0Q2xhc3NPckludGVyZmFjZShub2RlLCBwcm9wZXJ0aWVzKVxuICAgICAgY2FzZSAnZnVuY3Rpb24nOlxuICAgICAgY2FzZSAnY2FsbF9zaWduYXR1cmUnOlxuICAgICAgY2FzZSAnbWV0aG9kX3NpZ25hdHVyZSc6XG4gICAgICBjYXNlICdwcm9wZXJ0eV9zaWduYXR1cmUnOlxuICAgICAgY2FzZSAncHVibGljX2ZpZWxkX2RlZmluaXRpb24nOlxuICAgICAgY2FzZSAnbWV0aG9kX2RlZmluaXRpb24nOlxuICAgICAgY2FzZSAnbGV4aWNhbF9kZWNsYXJhdGlvbic6XG4gICAgICAgIHJldHVybiB0aGlzLnZpc2l0Tm9uVGVybWluYWwobm9kZSwgcHJvcGVydGllcyk7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aGlzLmxvZ2dlci5yZXBvcnQodGhpcy5zb3VyY2UsIG5vZGUsIEVycm9yVHlwZS5Ob2RlVHlwZU5vdFlldFN1cHBvcnRlZCk7XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIC8qIFN0YXRlbWVudHMgKi9cblxuICBwcml2YXRlIHZpc2l0RXhwb3J0U3RhdGVtZW50ID0gKG5vZGU6IFN5bnRheE5vZGUsIHByb3BlcnRpZXM/OiBQYXJ0aWFsPFR5cGVTY3JpcHRQcm9wZXJ0aWVzPik6IEFTVE5vZGUgPT4ge1xuICAgIGxldCBjaGlsZHJlbiA9IG5vZGUuY2hpbGRyZW4sIGRlZmF1bHRFeHBvcnQgPSBmYWxzZTtcbiAgICAvLyBSZW1vdmUgJ2V4cG9ydCcgc2luY2UgaXQncyBhbHdheXMgZmlyc3QgaW4gdGhlIGFycmF5XG4gICAgY2hpbGRyZW4uc2hpZnQoKTtcbiAgICBpZiAodGhpcy5oYXNEZWZhdWx0RXhwb3J0KG5vZGUpKSB7XG4gICAgICBkZWZhdWx0RXhwb3J0ID0gdHJ1ZTtcbiAgICAgIC8vIFJlbW92ZSAnZGVmYXVsdCcgZXhwb3J0XG4gICAgICBjaGlsZHJlbi5zaGlmdCgpO1xuICAgIH1cbiAgICBjb25zdCBjaGlsZCA9IGNoaWxkcmVuLnNoaWZ0KCk7XG4gICAgcmV0dXJuIHRoaXMudmlzaXROb2RlKGNoaWxkLCB7IGV4cG9ydHM6IHsgZXhwb3J0OiB0cnVlLCBkZWZhdWx0OiBkZWZhdWx0RXhwb3J0IH0gfSk7XG4gIH1cblxuICBwcml2YXRlIHZpc2l0RXhwcmVzc2lvblN0YXRlbWVudCA9IChub2RlOiBTeW50YXhOb2RlLCBwcm9wZXJ0aWVzOiBQYXJ0aWFsPFR5cGVTY3JpcHRQcm9wZXJ0aWVzPik6IEFTVE5vZGUgPT4ge1xuICAgIGxldCBjaGlsZHJlbiA9IG5vZGUuY2hpbGRyZW47XG4gICAgY29uc3QgY2hpbGQgPSBjaGlsZHJlbi5zaGlmdCgpO1xuXG4gICAgaWYgKG1hdGNoKGNoaWxkLCAnaW50ZXJuYWxfbW9kdWxlJykpIHtcbiAgICAgIHJldHVybiB0aGlzLnZpc2l0SW50ZXJuYWxNb2R1bGUoY2hpbGQsIHByb3BlcnRpZXMpXG4gICAgfVxuXG4gICAgaWYgKG1hdGNoKGNoaWxkLCAnZnVuY3Rpb24nKSkge1xuICAgICAgaWYgKHByb3BlcnRpZXMpIHJldHVybiB0aGlzLnZpc2l0Q29udGV4dChjaGlsZCwgcHJvcGVydGllcyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMudmlzaXROb25UZXJtaW5hbChjaGlsZClcbiAgfVxuXG4gIC8qIE1vZHVsZXMgKi9cblxuICBwcml2YXRlIHZpc2l0SW50ZXJuYWxNb2R1bGUgPSAobm9kZTogU3ludGF4Tm9kZSwgcHJvcGVydGllcz86IFBhcnRpYWw8VHlwZVNjcmlwdFByb3BlcnRpZXM+KTogQVNUTm9kZSA9PiB7XG4gICAgbGV0IGNoaWxkcmVuOiBBU1ROb2RlW10gPSBub2RlLmNoaWxkcmVuLm1hcChjaGlsZCA9PiB7XG4gICAgICBpZiAobWF0Y2goY2hpbGQsICdzdGF0ZW1lbnRfYmxvY2snKSkge1xuICAgICAgICByZXR1cm4gY3JlYXRlQVNUTm9kZSh0aGlzLnNvdXJjZSwgbm9kZSwgdGhpcy52aXNpdENoaWxkcmVuKHRoaXMuZmlsdGVyVHlwZShjaGlsZCwgJ2NvbW1lbnQnKSkpXG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcy52aXNpdE5vZGUoY2hpbGQpO1xuICAgIH0pO1xuICAgIHJldHVybiBjcmVhdGVBU1ROb2RlKHRoaXMuc291cmNlLCBub2RlLCBjaGlsZHJlbiwgT2JqZWN0LmFzc2lnbihwcm9wZXJ0aWVzIHx8IHt9LCB7IG5hbWVzcGFjZTogdHJ1ZSB9KSk7XG4gIH1cblxuXG4gIC8qIERlY2xhcmF0aW9ucyAqL1xuXG4gIHByaXZhdGUgdmlzaXRDbGFzc09ySW50ZXJmYWNlID0gKG5vZGU6IFN5bnRheE5vZGUsIHByb3BlcnRpZXM/OiBQYXJ0aWFsPFR5cGVTY3JpcHRQcm9wZXJ0aWVzPik6IEFTVE5vZGUgPT4ge1xuICAgIC8vIFNpbmNlICdpbnRlcmZhY2UnIG9yICdjbGFzcycgaXMgYWx3YXlzIGZpcnN0IGluIHRoZSBhcnJheVxuICAgIC8vIHdlJ2xsIG5lZWQgdG8gcmVtb3ZlIGl0IGZyb20gdGhlIGFycmF5LlxuICAgIGxldCBjaGlsZHJlbiA9IG5vZGUuY2hpbGRyZW47XG4gICAgY29uc3QgaW50ZXJmYWNlXyA9IGNoaWxkcmVuLnNoaWZ0KCk7XG4gICAgbGV0IGV4dGVuZHNfID0gZmFsc2UsIGltcGxlbWVudHNfID0gZmFsc2U7XG4gICAgaWYgKHRoaXMuaGFzSW5oZXJpdGFuY2Uobm9kZSkpIHtcbiAgICAgIGNvbnN0IGluaGVyaXRhbmNlID0gdGhpcy5nZXRJbmhlcml0YW5jZVR5cGUobm9kZSlcbiAgICAgIGV4dGVuZHNfID0gaW5oZXJpdGFuY2UgPT09ICdleHRlbmRzJztcbiAgICAgIGltcGxlbWVudHNfID0gaW5oZXJpdGFuY2UgPT09ICdpbXBsZW1lbnRzJztcbiAgICB9XG5cbiAgICBjb25zdCBub2RlXyA9IGNyZWF0ZUFTVE5vZGUoXG4gICAgICB0aGlzLnNvdXJjZSxcbiAgICAgIG5vZGUsXG4gICAgICB0aGlzLnZpc2l0Q2hpbGRyZW4oY2hpbGRyZW4pLFxuICAgICAgT2JqZWN0LmFzc2lnbihwcm9wZXJ0aWVzIHx8IHt9LCB7XG4gICAgICAgIGluaGVyaXRhbmNlOiB7XG4gICAgICAgICAgaW1wbGVtZW50czogaW1wbGVtZW50c18sXG4gICAgICAgICAgZXh0ZW5kczogZXh0ZW5kc19cbiAgICAgICAgfSBhcyBUeXBlU2NyaXB0SW5oZXJpdGFuY2VcbiAgICAgIH0pKTtcblxuICAgIGlmIChtYXRjaChub2RlLCAnY2xhc3MnKSkge1xuICAgICAgcmV0dXJuIG5vZGVfO1xuICAgIH1cbiAgICAvLyBPdmVyd3JpdGUgdGhlIG5vZGUgdHlwZSBmcm9tICdpbnRlcmZhY2VfZGVjbGFyYXRpb24nIHRvICdpbnRlcmZhY2UnXG4gICAgcmV0dXJuIE9iamVjdC5hc3NpZ24obm9kZV8sIHsgdHlwZTogaW50ZXJmYWNlXy50eXBlIH0pXG4gIH1cblxuICAvKiBOb24tdGVybWluYWxzICovXG5cbiAgcHJpdmF0ZSB2aXNpdE5vblRlcm1pbmFsID0gKG5vZGU6IFN5bnRheE5vZGUsIHByb3BlcnRpZXM/OiBQYXJ0aWFsPFR5cGVTY3JpcHRQcm9wZXJ0aWVzPik6IEFTVE5vZGUgPT4ge1xuICAgIGxldCBjaGlsZHJlbiA9IG5vZGUuY2hpbGRyZW47XG4gICAgLy8gSGFuZGxlIHNwZWNpYWwgY2FzZXMgd2hlcmUgc29tZSBub24tdGVybWluYWxzXG4gICAgLy8gY29udGFpbiBjb21tZW50cyB3aGljaCBpcyB3aGF0IHdlIGNhcmUgYWJvdXRcbiAgICBpZiAobWF0Y2gobm9kZSwgJ2NsYXNzX2JvZHknLCAnb2JqZWN0X3R5cGUnKSkge1xuICAgICAgY2hpbGRyZW4gPSB0aGlzLmZpbHRlclR5cGUobm9kZSwgJ2NvbW1lbnQnKTtcbiAgICB9XG4gICAgLy8gSGFuZGxlIHNwZWNpYWwgY2FzZXMgd2hlcmUgZXhwb3J0IHN0YXRlbWVudHMgaGF2ZSBub2RlIHByb3BlcnRpZXNcbiAgICBpZiAobWF0Y2gobm9kZSwgJ2V4cG9ydF9zdGF0ZW1lbnQnKSkge1xuICAgICAgcmV0dXJuIHRoaXMudmlzaXRFeHBvcnRTdGF0ZW1lbnQobm9kZSk7XG4gICAgfVxuXG4gICAgLy8gSGFuZGxlIHNwZWNpYWwgY2FzZXMgd2hlcmUgYW4gaW50ZXJuYWwgbW9kdWxlIGNvbnRhaW5zIG90aGVyIG5vZGVzXG4gICAgaWYgKG1hdGNoKG5vZGUsICdpbnRlcm5hbF9tb2R1bGUnKSkge1xuICAgICAgcmV0dXJuIHRoaXMudmlzaXRJbnRlcm5hbE1vZHVsZShub2RlLCBwcm9wZXJ0aWVzKTtcbiAgICB9XG5cbiAgICAvLyBIYW5kbGUgc3BlY2lhbCBjYXNlcyB3aGVyZSBhbiBpbnRlcm1hbF9tb2R1bGUgY2FuIGV4aXN0IGluIGFuIGV4cHJlc3Npb25fc3RhdGVtZW50XG4gICAgaWYgKG1hdGNoKG5vZGUsICdleHByZXNzaW9uX3N0YXRlbWVudCcpKSB7XG4gICAgICByZXR1cm4gdGhpcy52aXNpdEV4cHJlc3Npb25TdGF0ZW1lbnQobm9kZSwgcHJvcGVydGllcyk7XG4gICAgfVxuXG4gICAgaWYgKG1hdGNoKG5vZGUsICdmdW5jdGlvbicpIHx8IG1hdGNoKG5vZGUsICdtZXRob2RfZGVmaW5pdGlvbicpKSB7XG4gICAgICBfLnJlbW92ZShjaGlsZHJlbiwgY2hpbGQgPT4gbWF0Y2goY2hpbGQsICdzdGF0ZW1lbnRfYmxvY2snKSlcbiAgICAgIHJldHVybiBjcmVhdGVBU1ROb2RlKHRoaXMuc291cmNlLCBub2RlLCB0aGlzLnZpc2l0Q2hpbGRyZW4oY2hpbGRyZW4pLCBwcm9wZXJ0aWVzKTtcbiAgICB9XG5cbiAgICByZXR1cm4gY3JlYXRlQVNUTm9kZSh0aGlzLnNvdXJjZSwgbm9kZSwgdGhpcy52aXNpdENoaWxkcmVuKGNoaWxkcmVuKSwgcHJvcGVydGllcyk7XG4gIH1cblxuICAvKiBUZXJtaW5hbHMgKi9cblxuICBwcml2YXRlIHZpc2l0VGVybWluYWwgPSAobm9kZTogU3ludGF4Tm9kZSk6IEFTVE5vZGUgPT4ge1xuICAgIHJldHVybiBjcmVhdGVBU1ROb2RlKHRoaXMuc291cmNlLCBub2RlKVxuICB9XG59Il19 \ No newline at end of file diff --git a/build/src/utils/benchmark.d.ts b/build/src/utils/benchmark.d.ts new file mode 100644 index 0000000..d19bd5b --- /dev/null +++ b/build/src/utils/benchmark.d.ts @@ -0,0 +1 @@ +export default function benchmark(label: string, f: (x: T2) => T, ...args: T2[]): T; diff --git a/build/src/utils/benchmark.js b/build/src/utils/benchmark.js new file mode 100644 index 0000000..a6e49e6 --- /dev/null +++ b/build/src/utils/benchmark.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +function benchmark(label, f, ...args) { + console.time(label); + const result = f.apply(null, args); + console.timeEnd(label); + return result; +} +exports.default = benchmark; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmVuY2htYXJrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3V0aWxzL2JlbmNobWFyay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLFNBQXdCLFNBQVMsQ0FDL0IsS0FBYSxFQUNiLENBQWUsRUFDZixHQUFHLElBQVU7SUFFYixPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFBO0lBQ25CLE1BQU0sTUFBTSxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ25DLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDdkIsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQztBQVRELDRCQVNDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gYmVuY2htYXJrPFQsIFQyPihcbiAgbGFiZWw6IHN0cmluZyxcbiAgZjogKHg6IFQyKSA9PiBULFxuICAuLi5hcmdzOiBUMltdXG4pOiBUIHtcbiAgY29uc29sZS50aW1lKGxhYmVsKVxuICBjb25zdCByZXN1bHQgPSBmLmFwcGx5KG51bGwsIGFyZ3MpO1xuICBjb25zb2xlLnRpbWVFbmQobGFiZWwpO1xuICByZXR1cm4gcmVzdWx0O1xufSJdfQ== \ No newline at end of file diff --git a/build/src/utils/comment.d.ts b/build/src/utils/comment.d.ts new file mode 100644 index 0000000..ba9695a --- /dev/null +++ b/build/src/utils/comment.d.ts @@ -0,0 +1,8 @@ +import { SyntaxNode } from "tree-sitter"; +import Source from "../interfaces/Source"; +export declare const XDocRegex: RegExp; +export declare function isLegalComment(source: Source, node: SyntaxNode): boolean; +export declare function isJavaDocComment(source: Source, node: SyntaxNode): boolean; +export declare function isXDocComment(source: string, node?: SyntaxNode): boolean; +export declare function isXDocCommentBlock(source: string, node: SyntaxNode): boolean; +export declare function isXDocCommentFragment(source: string, node: SyntaxNode): boolean; diff --git a/build/src/utils/comment.js b/build/src/utils/comment.js new file mode 100644 index 0000000..dd61fb4 --- /dev/null +++ b/build/src/utils/comment.js @@ -0,0 +1,42 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const match_1 = require("./match"); +exports.XDocRegex = /@(\w+)([^{[(\n]*)?([\{\[\(][\s\S]*[\}\]\)]([\s]*(=|-)>.*)?)?([\s]*-(.)*)?/gmi; +function isLegalComment(source, node) { + const possibleTexts = [ + 'copyright', + 'terms and conditions', + 'license', + 'all rights reserved' + ]; + if (match_1.default(node, 'comment')) { + return possibleTexts.map(text => source.text + .substring(node.startIndex, node.endIndex) + .toLowerCase() + .includes(text)).includes(true); + } +} +exports.isLegalComment = isLegalComment; +function isJavaDocComment(source, node) { + const comment = source.text.substring(node.startIndex, node.endIndex); + // regexr.com/3ejvb + return /(\/\*\*)((\s*)(.*?)(\s))*(\*\/)/.test(comment); +} +exports.isJavaDocComment = isJavaDocComment; +function isXDocComment(source, node) { + let comment = source; + if (node) + comment = source.substring(node.startIndex, node.endIndex); + return exports.XDocRegex.test(comment); +} +exports.isXDocComment = isXDocComment; +function isXDocCommentBlock(source, node) { + const comment = source.substring(node.startIndex, node.endIndex); + return /#API/.test(comment) || /\`\`\`xdoc/.test(comment); +} +exports.isXDocCommentBlock = isXDocCommentBlock; +function isXDocCommentFragment(source, node) { + return !isXDocCommentBlock(source, node) && isXDocComment(source, node); +} +exports.isXDocCommentFragment = isXDocCommentFragment; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tbWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy91dGlscy9jb21tZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQ0EsbUNBQTRCO0FBR2YsUUFBQSxTQUFTLEdBQUcsOEVBQThFLENBQUM7QUFFeEcsU0FBZ0IsY0FBYyxDQUFFLE1BQWMsRUFBRSxJQUFnQjtJQUM5RCxNQUFNLGFBQWEsR0FBRztRQUNwQixXQUFXO1FBQ1gsc0JBQXNCO1FBQ3RCLFNBQVM7UUFDVCxxQkFBcUI7S0FDdEIsQ0FBQztJQUNGLElBQUksZUFBSyxDQUFDLElBQUksRUFBRSxTQUFTLENBQUMsRUFBRTtRQUMxQixPQUFPLGFBQWEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FDOUIsTUFBTSxDQUFDLElBQUk7YUFDUixTQUFTLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDO2FBQ3pDLFdBQVcsRUFBRTthQUNiLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FDbEIsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7S0FDbEI7QUFDSCxDQUFDO0FBZkQsd0NBZUM7QUFFRCxTQUFnQixnQkFBZ0IsQ0FBQyxNQUFjLEVBQUUsSUFBZ0I7SUFDL0QsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDdEUsbUJBQW1CO0lBQ25CLE9BQU8saUNBQWlDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFBO0FBQ3hELENBQUM7QUFKRCw0Q0FJQztBQUVELFNBQWdCLGFBQWEsQ0FBQyxNQUFhLEVBQUUsSUFBaUI7SUFDNUQsSUFBSSxPQUFPLEdBQUcsTUFBTSxDQUFDO0lBQ3JCLElBQUksSUFBSTtRQUFFLE9BQU8sR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3JFLE9BQU8saUJBQVMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7QUFDakMsQ0FBQztBQUpELHNDQUlDO0FBRUQsU0FBZ0Isa0JBQWtCLENBQUMsTUFBYyxFQUFFLElBQWdCO0lBQ2pFLE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDakUsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLFlBQVksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUE7QUFDM0QsQ0FBQztBQUhELGdEQUdDO0FBRUQsU0FBZ0IscUJBQXFCLENBQUMsTUFBYyxFQUFFLElBQWdCO0lBQ3BFLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLElBQUksYUFBYSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsQ0FBQztBQUMxRSxDQUFDO0FBRkQsc0RBRUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBTeW50YXhOb2RlIH0gZnJvbSBcInRyZWUtc2l0dGVyXCI7XG5pbXBvcnQgbWF0Y2ggZnJvbSBcIi4vbWF0Y2hcIjtcbmltcG9ydCBTb3VyY2UgZnJvbSBcIi4uL2ludGVyZmFjZXMvU291cmNlXCI7XG5cbmV4cG9ydCBjb25zdCBYRG9jUmVnZXggPSAvQChcXHcrKShbXntbKFxcbl0qKT8oW1xce1xcW1xcKF1bXFxzXFxTXSpbXFx9XFxdXFwpXShbXFxzXSooPXwtKT4uKik/KT8oW1xcc10qLSguKSopPy9nbWk7XG5cbmV4cG9ydCBmdW5jdGlvbiBpc0xlZ2FsQ29tbWVudCAoc291cmNlOiBTb3VyY2UsIG5vZGU6IFN5bnRheE5vZGUpIHtcbiAgY29uc3QgcG9zc2libGVUZXh0cyA9IFtcbiAgICAnY29weXJpZ2h0JyxcbiAgICAndGVybXMgYW5kIGNvbmRpdGlvbnMnLFxuICAgICdsaWNlbnNlJyxcbiAgICAnYWxsIHJpZ2h0cyByZXNlcnZlZCdcbiAgXTtcbiAgaWYgKG1hdGNoKG5vZGUsICdjb21tZW50JykpIHtcbiAgICByZXR1cm4gcG9zc2libGVUZXh0cy5tYXAodGV4dCA9PlxuICAgICAgc291cmNlLnRleHRcbiAgICAgICAgLnN1YnN0cmluZyhub2RlLnN0YXJ0SW5kZXgsIG5vZGUuZW5kSW5kZXgpXG4gICAgICAgIC50b0xvd2VyQ2FzZSgpXG4gICAgICAgIC5pbmNsdWRlcyh0ZXh0KVxuICAgICkuaW5jbHVkZXModHJ1ZSk7XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzSmF2YURvY0NvbW1lbnQoc291cmNlOiBTb3VyY2UsIG5vZGU6IFN5bnRheE5vZGUpIHtcbiAgY29uc3QgY29tbWVudCA9IHNvdXJjZS50ZXh0LnN1YnN0cmluZyhub2RlLnN0YXJ0SW5kZXgsIG5vZGUuZW5kSW5kZXgpO1xuICAvLyByZWdleHIuY29tLzNlanZiXG4gIHJldHVybiAvKFxcL1xcKlxcKikoKFxccyopKC4qPykoXFxzKSkqKFxcKlxcLykvLnRlc3QoY29tbWVudClcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzWERvY0NvbW1lbnQoc291cmNlOnN0cmluZywgbm9kZT86IFN5bnRheE5vZGUpIHtcbiAgbGV0IGNvbW1lbnQgPSBzb3VyY2U7XG4gIGlmIChub2RlKSBjb21tZW50ID0gc291cmNlLnN1YnN0cmluZyhub2RlLnN0YXJ0SW5kZXgsIG5vZGUuZW5kSW5kZXgpO1xuICByZXR1cm4gWERvY1JlZ2V4LnRlc3QoY29tbWVudCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc1hEb2NDb21tZW50QmxvY2soc291cmNlOiBzdHJpbmcsIG5vZGU6IFN5bnRheE5vZGUpIHtcbiAgY29uc3QgY29tbWVudCA9IHNvdXJjZS5zdWJzdHJpbmcobm9kZS5zdGFydEluZGV4LCBub2RlLmVuZEluZGV4KTtcbiAgcmV0dXJuIC8jQVBJLy50ZXN0KGNvbW1lbnQpIHx8IC9cXGBcXGBcXGB4ZG9jLy50ZXN0KGNvbW1lbnQpXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc1hEb2NDb21tZW50RnJhZ21lbnQoc291cmNlOiBzdHJpbmcsIG5vZGU6IFN5bnRheE5vZGUpIHtcbiAgcmV0dXJuICFpc1hEb2NDb21tZW50QmxvY2soc291cmNlLCBub2RlKSAmJiBpc1hEb2NDb21tZW50KHNvdXJjZSwgbm9kZSk7XG59Il19 \ No newline at end of file diff --git a/build/src/utils/log.d.ts b/build/src/utils/log.d.ts new file mode 100644 index 0000000..d0dade9 --- /dev/null +++ b/build/src/utils/log.d.ts @@ -0,0 +1,11 @@ +import { Log, LogOptions } from 'mr-doc-utils'; +import Source from '../interfaces/Source'; +import { SyntaxNode } from 'tree-sitter'; +export declare enum ErrorType { + NodeTypeNotYetSupported = 0, + TreeSitterParseError = 1 +} +export default class ParserLogger extends Log { + constructor(options?: LogOptions); + report: (source: Source, node: SyntaxNode, error: ErrorType) => void; +} diff --git a/build/src/utils/log.js b/build/src/utils/log.js new file mode 100644 index 0000000..7a12499 --- /dev/null +++ b/build/src/utils/log.js @@ -0,0 +1,31 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const mr_doc_utils_1 = require("mr-doc-utils"); +const range_1 = require("./range"); +var ErrorType; +(function (ErrorType) { + ErrorType[ErrorType["NodeTypeNotYetSupported"] = 0] = "NodeTypeNotYetSupported"; + ErrorType[ErrorType["TreeSitterParseError"] = 1] = "TreeSitterParseError"; +})(ErrorType = exports.ErrorType || (exports.ErrorType = {})); +class ParserLogger extends mr_doc_utils_1.Log { + constructor(options) { + super('mr-doc::parser', options); + this.report = (source, node, error) => { + const location = range_1.default(node).location; + const sameLine = location.row.start === location.row.end; + const getLineRange = () => sameLine ? location.row.start + 1 : location.row.start + 1 + ' - ' + location.row.end + 1; + const culprit = `Line${sameLine ? '' : 's'} ${getLineRange()} in '${source.path}'`; + switch (error) { + case ErrorType.NodeTypeNotYetSupported: + this.info(`'${node.type.replace(/[_]/g, ' ')}' is not yet supported:\n${culprit}`); + break; + case ErrorType.TreeSitterParseError: + this.error(`'tree-sitter' was not able to parse the program:\n${culprit}`); + default: + break; + } + }; + } +} +exports.default = ParserLogger; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3V0aWxzL2xvZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLCtDQUErQztBQUcvQyxtQ0FBNEI7QUFFNUIsSUFBWSxTQUdYO0FBSEQsV0FBWSxTQUFTO0lBQ2pCLCtFQUF1QixDQUFBO0lBQ3ZCLHlFQUFvQixDQUFBO0FBQ3hCLENBQUMsRUFIVyxTQUFTLEdBQVQsaUJBQVMsS0FBVCxpQkFBUyxRQUdwQjtBQUVELE1BQXFCLFlBQWEsU0FBUSxrQkFBRztJQUN6QyxZQUFZLE9BQW9CO1FBQzVCLEtBQUssQ0FBQyxnQkFBZ0IsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUVyQyxXQUFNLEdBQUcsQ0FBQyxNQUFjLEVBQUUsSUFBZ0IsRUFBRSxLQUFnQixFQUFRLEVBQUU7WUFDbEUsTUFBTSxRQUFRLEdBQUcsZUFBSyxDQUFDLElBQUksQ0FBQyxDQUFDLFFBQVEsQ0FBQztZQUN0QyxNQUFNLFFBQVEsR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLEtBQUssS0FBSyxRQUFRLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQztZQUN6RCxNQUFNLFlBQVksR0FBRyxHQUFHLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxHQUFHLEtBQUssR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUM7WUFDckgsTUFBTSxPQUFPLEdBQUcsT0FBTyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLFlBQVksRUFBRSxRQUFRLE1BQU0sQ0FBQyxJQUFJLEdBQUcsQ0FBQztZQUNuRixRQUFRLEtBQUssRUFBRTtnQkFDWCxLQUFLLFNBQVMsQ0FBQyx1QkFBdUI7b0JBQ2xDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLDRCQUE0QixPQUFPLEVBQUUsQ0FBQyxDQUFBO29CQUNsRixNQUFNO2dCQUNWLEtBQUssU0FBUyxDQUFDLG9CQUFvQjtvQkFDL0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxxREFBcUQsT0FBTyxFQUFFLENBQUMsQ0FBQTtnQkFDOUU7b0JBQ0ksTUFBTTthQUNiO1FBQ0wsQ0FBQyxDQUFBO0lBZkQsQ0FBQztDQWdCSjtBQW5CRCwrQkFtQkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBMb2csIExvZ09wdGlvbnMgfSBmcm9tICdtci1kb2MtdXRpbHMnO1xuaW1wb3J0IFNvdXJjZSBmcm9tICcuLi9pbnRlcmZhY2VzL1NvdXJjZSc7XG5pbXBvcnQgeyBTeW50YXhOb2RlIH0gZnJvbSAndHJlZS1zaXR0ZXInO1xuaW1wb3J0IHJhbmdlIGZyb20gJy4vcmFuZ2UnO1xuXG5leHBvcnQgZW51bSBFcnJvclR5cGUge1xuICAgIE5vZGVUeXBlTm90WWV0U3VwcG9ydGVkLFxuICAgIFRyZWVTaXR0ZXJQYXJzZUVycm9yXG59XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFBhcnNlckxvZ2dlciBleHRlbmRzIExvZyB7XG4gICAgY29uc3RydWN0b3Iob3B0aW9ucz86IExvZ09wdGlvbnMpIHtcbiAgICAgICAgc3VwZXIoJ21yLWRvYzo6cGFyc2VyJywgb3B0aW9ucyk7XG4gICAgfVxuICAgIHJlcG9ydCA9IChzb3VyY2U6IFNvdXJjZSwgbm9kZTogU3ludGF4Tm9kZSwgZXJyb3I6IEVycm9yVHlwZSk6IHZvaWQgPT4ge1xuICAgICAgICBjb25zdCBsb2NhdGlvbiA9IHJhbmdlKG5vZGUpLmxvY2F0aW9uO1xuICAgICAgICBjb25zdCBzYW1lTGluZSA9IGxvY2F0aW9uLnJvdy5zdGFydCA9PT0gbG9jYXRpb24ucm93LmVuZDtcbiAgICAgICAgY29uc3QgZ2V0TGluZVJhbmdlID0gKCkgPT4gc2FtZUxpbmUgPyBsb2NhdGlvbi5yb3cuc3RhcnQgKyAxIDogbG9jYXRpb24ucm93LnN0YXJ0ICsgMSArICcgLSAnICsgbG9jYXRpb24ucm93LmVuZCArIDE7XG4gICAgICAgIGNvbnN0IGN1bHByaXQgPSBgTGluZSR7c2FtZUxpbmUgPyAnJyA6ICdzJ30gJHtnZXRMaW5lUmFuZ2UoKX0gaW4gJyR7c291cmNlLnBhdGh9J2A7XG4gICAgICAgIHN3aXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIGNhc2UgRXJyb3JUeXBlLk5vZGVUeXBlTm90WWV0U3VwcG9ydGVkOlxuICAgICAgICAgICAgICAgIHRoaXMuaW5mbyhgJyR7bm9kZS50eXBlLnJlcGxhY2UoL1tfXS9nLCAnICcpfScgaXMgbm90IHlldCBzdXBwb3J0ZWQ6XFxuJHtjdWxwcml0fWApXG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIEVycm9yVHlwZS5UcmVlU2l0dGVyUGFyc2VFcnJvcjpcbiAgICAgICAgICAgICAgICB0aGlzLmVycm9yKGAndHJlZS1zaXR0ZXInIHdhcyBub3QgYWJsZSB0byBwYXJzZSB0aGUgcHJvZ3JhbTpcXG4ke2N1bHByaXR9YClcbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICB9XG59Il19 \ No newline at end of file diff --git a/build/src/utils/match.d.ts b/build/src/utils/match.d.ts new file mode 100644 index 0000000..2fde18b --- /dev/null +++ b/build/src/utils/match.d.ts @@ -0,0 +1,10 @@ +import { SyntaxNode } from "tree-sitter"; +/** + * Determines whether a node is a certain type. + * ``` + * @param node: SyntaxNode - The node to compare. + * @param type: string - The node type to match. + * @return: boolean + * ``` + */ +export default function match(node: SyntaxNode, ...types: string[]): boolean; diff --git a/build/src/utils/match.js b/build/src/utils/match.js new file mode 100644 index 0000000..74e0c8d --- /dev/null +++ b/build/src/utils/match.js @@ -0,0 +1,21 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +/** + * Determines whether a node is a certain type. + * ``` + * @param node: SyntaxNode - The node to compare. + * @param type: string - The node type to match. + * @return: boolean + * ``` + */ +function match(node, ...types) { + for (let i = 0; i < types.length; i++) { + const type = types[i]; + if (node.type === type) { + return true; + } + } + return false; +} +exports.default = match; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWF0Y2guanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdXRpbHMvbWF0Y2gudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFFQTs7Ozs7OztHQU9HO0FBQ0gsU0FBd0IsS0FBSyxDQUFDLElBQWdCLEVBQUUsR0FBRyxLQUFlO0lBQ2hFLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ3JDLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN0QixJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssSUFBSSxFQUFFO1lBQ3RCLE9BQU8sSUFBSSxDQUFDO1NBQ2I7S0FDRjtJQUNELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQVJELHdCQVFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgU3ludGF4Tm9kZSB9IGZyb20gXCJ0cmVlLXNpdHRlclwiO1xuXG4vKipcbiAqIERldGVybWluZXMgd2hldGhlciBhIG5vZGUgaXMgYSBjZXJ0YWluIHR5cGUuXG4gKiBgYGBcbiAqIEBwYXJhbSBub2RlOiBTeW50YXhOb2RlIC0gVGhlIG5vZGUgdG8gY29tcGFyZS5cbiAqIEBwYXJhbSB0eXBlOiBzdHJpbmcgIC0gVGhlIG5vZGUgdHlwZSB0byBtYXRjaC5cbiAqIEByZXR1cm46IGJvb2xlYW5cbiAqIGBgYFxuICovXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBtYXRjaChub2RlOiBTeW50YXhOb2RlLCAuLi50eXBlczogc3RyaW5nW10pOiBib29sZWFuIHtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB0eXBlcy5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IHR5cGUgPSB0eXBlc1tpXTtcbiAgICBpZiAobm9kZS50eXBlID09PSB0eXBlKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGZhbHNlO1xufSJdfQ== \ No newline at end of file diff --git a/build/src/utils/range.d.ts b/build/src/utils/range.d.ts new file mode 100644 index 0000000..72894b8 --- /dev/null +++ b/build/src/utils/range.d.ts @@ -0,0 +1,3 @@ +import * as Parser from 'tree-sitter'; +import TextRange from '../interfaces/TextRange'; +export default function range(node: Parser.SyntaxNode): TextRange; diff --git a/build/src/utils/range.js b/build/src/utils/range.js new file mode 100644 index 0000000..e8ee5d6 --- /dev/null +++ b/build/src/utils/range.js @@ -0,0 +1,16 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +function range(node) { + return { + position: { + start: node.startIndex, + end: node.endIndex + }, + location: { + row: { start: node.startPosition.row, end: node.endPosition.row }, + column: { start: node.startPosition.column, end: node.endPosition.column } + } + }; +} +exports.default = range; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmFuZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdXRpbHMvcmFuZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFHQSxTQUF3QixLQUFLLENBQUMsSUFBdUI7SUFDbkQsT0FBTztRQUNMLFFBQVEsRUFBRTtZQUNSLEtBQUssRUFBRSxJQUFJLENBQUMsVUFBVTtZQUN0QixHQUFHLEVBQUUsSUFBSSxDQUFDLFFBQVE7U0FDbkI7UUFDRCxRQUFRLEVBQUU7WUFDUixHQUFHLEVBQUUsRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxFQUFFO1lBQ2pFLE1BQU0sRUFBRSxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEVBQUU7U0FDM0U7S0FDRixDQUFBO0FBQ0gsQ0FBQztBQVhELHdCQVdDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgUGFyc2VyIGZyb20gJ3RyZWUtc2l0dGVyJztcbmltcG9ydCBUZXh0UmFuZ2UgZnJvbSAnLi4vaW50ZXJmYWNlcy9UZXh0UmFuZ2UnO1xuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiByYW5nZShub2RlOiBQYXJzZXIuU3ludGF4Tm9kZSk6IFRleHRSYW5nZSB7XG4gIHJldHVybiB7XG4gICAgcG9zaXRpb246IHtcbiAgICAgIHN0YXJ0OiBub2RlLnN0YXJ0SW5kZXgsXG4gICAgICBlbmQ6IG5vZGUuZW5kSW5kZXhcbiAgICB9LFxuICAgIGxvY2F0aW9uOiB7XG4gICAgICByb3c6IHsgc3RhcnQ6IG5vZGUuc3RhcnRQb3NpdGlvbi5yb3csIGVuZDogbm9kZS5lbmRQb3NpdGlvbi5yb3cgfSxcbiAgICAgIGNvbHVtbjogeyBzdGFydDogbm9kZS5zdGFydFBvc2l0aW9uLmNvbHVtbiwgZW5kOiBub2RlLmVuZFBvc2l0aW9uLmNvbHVtbiB9XG4gICAgfVxuICB9XG59Il19 \ No newline at end of file diff --git a/build/src/utils/sibling.d.ts b/build/src/utils/sibling.d.ts new file mode 100644 index 0000000..692d7b0 --- /dev/null +++ b/build/src/utils/sibling.d.ts @@ -0,0 +1,2 @@ +import { SyntaxNode } from "tree-sitter"; +export declare function sibling(node: SyntaxNode, children?: SyntaxNode[], filter?: () => boolean): SyntaxNode; diff --git a/build/src/utils/sibling.js b/build/src/utils/sibling.js new file mode 100644 index 0000000..fe01442 --- /dev/null +++ b/build/src/utils/sibling.js @@ -0,0 +1,15 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +function sibling(node, children, filter) { + if (node) { + if (children) { + const index = filter ? + children.filter(filter).indexOf(node) : + children.indexOf(node); + return children[index + 1]; + } + return node.nextSibling; + } +} +exports.sibling = sibling; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2libGluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy91dGlscy9zaWJsaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBRUEsU0FBZ0IsT0FBTyxDQUNyQixJQUFnQixFQUNoQixRQUF1QixFQUN2QixNQUFzQjtJQUV0QixJQUFJLElBQUksRUFBRTtRQUNSLElBQUksUUFBUSxFQUFFO1lBQ1osTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLENBQUM7Z0JBQ3BCLFFBQVEsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7Z0JBQ3ZDLFFBQVEsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDekIsT0FBTyxRQUFRLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO1NBQzVCO1FBQ0QsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDO0tBQ3pCO0FBQ0gsQ0FBQztBQWRELDBCQWNDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgU3ludGF4Tm9kZSB9IGZyb20gXCJ0cmVlLXNpdHRlclwiO1xuXG5leHBvcnQgZnVuY3Rpb24gc2libGluZyhcbiAgbm9kZTogU3ludGF4Tm9kZSxcbiAgY2hpbGRyZW4/OiBTeW50YXhOb2RlW10sXG4gIGZpbHRlcj86ICgpID0+IGJvb2xlYW5cbikge1xuICBpZiAobm9kZSkge1xuICAgIGlmIChjaGlsZHJlbikge1xuICAgICAgY29uc3QgaW5kZXggPSBmaWx0ZXIgP1xuICAgICAgICBjaGlsZHJlbi5maWx0ZXIoZmlsdGVyKS5pbmRleE9mKG5vZGUpIDpcbiAgICAgICAgY2hpbGRyZW4uaW5kZXhPZihub2RlKTtcbiAgICAgIHJldHVybiBjaGlsZHJlbltpbmRleCArIDFdO1xuICAgIH1cbiAgICByZXR1cm4gbm9kZS5uZXh0U2libGluZztcbiAgfVxufSJdfQ== \ No newline at end of file diff --git a/build/src/utils/text.d.ts b/build/src/utils/text.d.ts new file mode 100644 index 0000000..dc2e7af --- /dev/null +++ b/build/src/utils/text.d.ts @@ -0,0 +1,11 @@ +import { SyntaxNode } from "tree-sitter"; +import Source from "../interfaces/Source"; +/** + * Returns the context string + * + * # API + * + * @param source: IFile - The source file. + * @param node: SyntaxNode - The syntax node. + */ +export declare function text(source: Source, node: SyntaxNode): string; diff --git a/build/src/utils/text.js b/build/src/utils/text.js new file mode 100644 index 0000000..c4b2bc3 --- /dev/null +++ b/build/src/utils/text.js @@ -0,0 +1,15 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +/** + * Returns the context string + * + * # API + * + * @param source: IFile - The source file. + * @param node: SyntaxNode - The syntax node. + */ +function text(source, node) { + return source.text.substring(node.startIndex, node.endIndex); +} +exports.text = text; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGV4dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy91dGlscy90ZXh0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBR0E7Ozs7Ozs7R0FPRztBQUNILFNBQWdCLElBQUksQ0FBQyxNQUFjLEVBQUUsSUFBZ0I7SUFDbkQsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUMvRCxDQUFDO0FBRkQsb0JBRUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBTeW50YXhOb2RlIH0gZnJvbSBcInRyZWUtc2l0dGVyXCI7XG5pbXBvcnQgU291cmNlIGZyb20gXCIuLi9pbnRlcmZhY2VzL1NvdXJjZVwiO1xuXG4vKipcbiAqIFJldHVybnMgdGhlIGNvbnRleHQgc3RyaW5nXG4gKiBcbiAqICMgQVBJXG4gKiBcbiAqIEBwYXJhbSBzb3VyY2U6IElGaWxlIC0gVGhlIHNvdXJjZSBmaWxlLlxuICogQHBhcmFtIG5vZGU6IFN5bnRheE5vZGUgLSBUaGUgc3ludGF4IG5vZGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0ZXh0KHNvdXJjZTogU291cmNlLCBub2RlOiBTeW50YXhOb2RlKSB7XG4gIHJldHVybiBzb3VyY2UudGV4dC5zdWJzdHJpbmcobm9kZS5zdGFydEluZGV4LCBub2RlLmVuZEluZGV4KTtcbn0iXX0= \ No newline at end of file diff --git a/build/src/utils/walk.d.ts b/build/src/utils/walk.d.ts new file mode 100644 index 0000000..a4ef2e4 --- /dev/null +++ b/build/src/utils/walk.d.ts @@ -0,0 +1,3 @@ +import { SyntaxNode } from "tree-sitter"; +import { Node } from '../lang/common/node'; +export default function walk(node: SyntaxNode): Node; diff --git a/build/src/utils/walk.js b/build/src/utils/walk.js new file mode 100644 index 0000000..d2e0acd --- /dev/null +++ b/build/src/utils/walk.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const node_1 = require("../lang/common/node"); +function walk(node) { + let node_ = new node_1.Node(node); + node_.syntaxNode.children.map(child => walk(child)); + return node_; +} +exports.default = walk; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2Fsay5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy91dGlscy93YWxrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQ0EsOENBQTBDO0FBQzFDLFNBQXdCLElBQUksQ0FBQyxJQUFnQjtJQUMzQyxJQUFJLEtBQUssR0FBRyxJQUFJLFdBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMzQixLQUFLLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQTtJQUNuRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFKRCx1QkFJQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFN5bnRheE5vZGUgfSBmcm9tIFwidHJlZS1zaXR0ZXJcIjtcbmltcG9ydCB7IE5vZGUgfSBmcm9tICcuLi9sYW5nL2NvbW1vbi9ub2RlJ1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gd2Fsayhub2RlOiBTeW50YXhOb2RlKSB7XG4gIGxldCBub2RlXyA9IG5ldyBOb2RlKG5vZGUpO1xuICBub2RlXy5zeW50YXhOb2RlLmNoaWxkcmVuLm1hcChjaGlsZCA9PiB3YWxrKGNoaWxkKSlcbiAgcmV0dXJuIG5vZGVfO1xufSJdfQ== \ No newline at end of file diff --git a/corpus/ReactElementValidator.txt b/corpus/ReactElementValidator.txt new file mode 100644 index 0000000..6132f57 --- /dev/null +++ b/corpus/ReactElementValidator.txt @@ -0,0 +1,367 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * ReactElementValidator provides a wrapper around a element factory + * which validates the props passed to the element. This is intended to be + * used only in DEV and could be replaced by a static type checker for languages + * that support it. + */ + +import lowPriorityWarning from 'shared/lowPriorityWarning'; +import isValidElementType from 'shared/isValidElementType'; +import getComponentName from 'shared/getComponentName'; +import { + getIteratorFn, + REACT_FORWARD_REF_TYPE, + REACT_FRAGMENT_TYPE, + REACT_ELEMENT_TYPE, +} from 'shared/ReactSymbols'; +import checkPropTypes from 'prop-types/checkPropTypes'; +import warning from 'shared/warning'; +import warningWithoutStack from 'shared/warningWithoutStack'; + +import ReactCurrentOwner from './ReactCurrentOwner'; +import {isValidElement, createElement, cloneElement} from './ReactElement'; +import ReactDebugCurrentFrame, { + setCurrentlyValidatingElement, +} from './ReactDebugCurrentFrame'; + +let propTypesMisspellWarningShown; + +if (__DEV__) { + propTypesMisspellWarningShown = false; +} + +function getDeclarationErrorAddendum() { + if (ReactCurrentOwner.current) { + const name = getComponentName(ReactCurrentOwner.current.type); + if (name) { + return '\n\nCheck the render method of `' + name + '`.'; + } + } + return ''; +} + +function getSourceInfoErrorAddendum(elementProps) { + if ( + elementProps !== null && + elementProps !== undefined && + elementProps.__source !== undefined + ) { + const source = elementProps.__source; + const fileName = source.fileName.replace(/^.*[\\\/]/, ''); + const lineNumber = source.lineNumber; + return '\n\nCheck your code at ' + fileName + ':' + lineNumber + '.'; + } + return ''; +} + +/** + * Warn if there's no key explicitly set on dynamic arrays of children or + * object keys are not valid. This allows us to keep track of children between + * updates. + */ +const ownerHasKeyUseWarning = {}; + +function getCurrentComponentErrorInfo(parentType) { + let info = getDeclarationErrorAddendum(); + + if (!info) { + const parentName = + typeof parentType === 'string' + ? parentType + : parentType.displayName || parentType.name; + if (parentName) { + info = `\n\nCheck the top-level render call using <${parentName}>.`; + } + } + return info; +} + +/** + * Warn if the element doesn't have an explicit key assigned to it. + * This element is in an array. The array could grow and shrink or be + * reordered. All children that haven't already been validated are required to + * have a "key" property assigned to it. Error statuses are cached so a warning + * will only be shown once. + * + * @internal + * @param element: ReactElement - Element that requires a key. + * @param parentType: any - element's parent's type. + */ +function validateExplicitKey(element, parentType) { + if (!element._store || element._store.validated || element.key != null) { + return; + } + element._store.validated = true; + + const currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType); + if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { + return; + } + ownerHasKeyUseWarning[currentComponentErrorInfo] = true; + + // Usually the current owner is the offender, but if it accepts children as a + // property, it may be the creator of the child that's responsible for + // assigning it a key. + let childOwner = ''; + if ( + element && + element._owner && + element._owner !== ReactCurrentOwner.current + ) { + // Give the component that originally created this child. + childOwner = ` It was passed a child from ${getComponentName( + element._owner.type, + )}.`; + } + + setCurrentlyValidatingElement(element); + if (__DEV__) { + warning( + false, + 'Each child in an array or iterator should have a unique "key" prop.' + + '%s%s See https://fb.me/react-warning-keys for more information.', + currentComponentErrorInfo, + childOwner, + ); + } + setCurrentlyValidatingElement(null); +} + +/** + * Ensure that every element either is passed in a static location, in an + * array with an explicit keys property defined, or in an object literal + * with valid key property. + * + * @internal + * @param node: ReactNode - Statically passed child of any type. + * @param parentType: any - node's parent's type. + */ +function validateChildKeys(node, parentType) { + if (typeof node !== 'object') { + return; + } + if (Array.isArray(node)) { + for (let i = 0; i < node.length; i++) { + const child = node[i]; + if (isValidElement(child)) { + validateExplicitKey(child, parentType); + } + } + } else if (isValidElement(node)) { + // This element was passed in a valid location. + if (node._store) { + node._store.validated = true; + } + } else if (node) { + const iteratorFn = getIteratorFn(node); + if (typeof iteratorFn === 'function') { + // Entry iterators used to provide implicit keys, + // but now we print a separate warning for them later. + if (iteratorFn !== node.entries) { + const iterator = iteratorFn.call(node); + let step; + while (!(step = iterator.next()).done) { + if (isValidElement(step.value)) { + validateExplicitKey(step.value, parentType); + } + } + } + } + } +} + +/** + * Given an element, validate that its props follow the propTypes definition, + * provided by the type. + * + * @param element: ReactElement + */ +function validatePropTypes(element) { + const type = element.type; + let name, propTypes; + if (typeof type === 'function') { + // Class or functional component + name = type.displayName || type.name; + propTypes = type.propTypes; + } else if ( + typeof type === 'object' && + type !== null && + type.$$typeof === REACT_FORWARD_REF_TYPE + ) { + // ForwardRef + const functionName = type.render.displayName || type.render.name || ''; + name = functionName !== '' ? `ForwardRef(${functionName})` : 'ForwardRef'; + propTypes = type.propTypes; + } else { + return; + } + if (propTypes) { + setCurrentlyValidatingElement(element); + checkPropTypes( + propTypes, + element.props, + 'prop', + name, + ReactDebugCurrentFrame.getStackAddendum, + ); + setCurrentlyValidatingElement(null); + } else if (type.PropTypes !== undefined && !propTypesMisspellWarningShown) { + propTypesMisspellWarningShown = true; + warningWithoutStack( + false, + 'Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?', + name || 'Unknown', + ); + } + if (typeof type.getDefaultProps === 'function') { + warningWithoutStack( + type.getDefaultProps.isReactClassApproved, + 'getDefaultProps is only used on classic React.createClass ' + + 'definitions. Use a static property named `defaultProps` instead.', + ); + } +} + +/** + * Given a fragment, validate that it can only be provided with fragment props + * @param fragment: ReactElement + */ +function validateFragmentProps(fragment) { + setCurrentlyValidatingElement(fragment); + + const keys = Object.keys(fragment.props); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + if (key !== 'children' && key !== 'key') { + warning( + false, + 'Invalid prop `%s` supplied to `React.Fragment`. ' + + 'React.Fragment can only have `key` and `children` props.', + key, + ); + break; + } + } + + if (fragment.ref !== null) { + warning(false, 'Invalid attribute `ref` supplied to `React.Fragment`.'); + } + + setCurrentlyValidatingElement(null); +} + +export function createElementWithValidation(type, props, children) { + const validType = isValidElementType(type); + + // We warn in this case but don't throw. We expect the element creation to + // succeed and there will likely be errors in render. + if (!validType) { + let info = ''; + if ( + type === undefined || + (typeof type === 'object' && + type !== null && + Object.keys(type).length === 0) + ) { + info += + ' You likely forgot to export your component from the file ' + + "it's defined in, or you might have mixed up default and named imports."; + } + + const sourceInfo = getSourceInfoErrorAddendum(props); + if (sourceInfo) { + info += sourceInfo; + } else { + info += getDeclarationErrorAddendum(); + } + + let typeString; + if (type === null) { + typeString = 'null'; + } else if (Array.isArray(type)) { + typeString = 'array'; + } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) { + typeString = `<${getComponentName(type.type) || 'Unknown'} />`; + info = + ' Did you accidentally export a JSX literal instead of a component?'; + } else { + typeString = typeof type; + } + + warning( + false, + 'React.createElement: type is invalid -- expected a string (for ' + + 'built-in components) or a class/function (for composite ' + + 'components) but got: %s.%s', + typeString, + info, + ); + } + + const element = createElement.apply(this, arguments); + + // The result can be nullish if a mock or a custom function is used. + // TODO: Drop this when these are no longer allowed as the type argument. + if (element == null) { + return element; + } + + // Skip key warning if the type isn't valid since our key validation logic + // doesn't expect a non-string/function type and can throw confusing errors. + // We don't want exception behavior to differ between dev and prod. + // (Rendering will throw with a helpful message and as soon as the type is + // fixed, the key warnings will appear.) + if (validType) { + for (let i = 2; i < arguments.length; i++) { + validateChildKeys(arguments[i], type); + } + } + + if (type === REACT_FRAGMENT_TYPE) { + validateFragmentProps(element); + } else { + validatePropTypes(element); + } + + return element; +} + +export function createFactoryWithValidation(type) { + const validatedFactory = createElementWithValidation.bind(null, type); + validatedFactory.type = type; + // Legacy hook: remove it + if (__DEV__) { + Object.defineProperty(validatedFactory, 'type', { + enumerable: false, + get: function() { + lowPriorityWarning( + false, + 'Factory.type is deprecated. Access the class directly ' + + 'before passing it to createFactory.', + ); + Object.defineProperty(this, 'type', { + value: type, + }); + return type; + }, + }); + } + + return validatedFactory; +} + +export function cloneElementWithValidation(element, props, children) { + const newElement = cloneElement.apply(this, arguments); + for (let i = 2; i < arguments.length; i++) { + validateChildKeys(arguments[i], newElement.type); + } + validatePropTypes(newElement); + return newElement; +} \ No newline at end of file diff --git a/corpus/example.js b/corpus/example.js new file mode 100644 index 0000000..4a9c33f --- /dev/null +++ b/corpus/example.js @@ -0,0 +1,13 @@ +/** + * + * @param x - description + */ +class A { + /** + * @method method + */ + method () { + /* Some method */ + const x = 1; + } +} \ No newline at end of file diff --git a/corpus/example.ts b/corpus/example.ts new file mode 100644 index 0000000..2f43745 --- /dev/null +++ b/corpus/example.ts @@ -0,0 +1,8 @@ +export namespace X { + /** + * + */ + export function name(...args) { + + } +} \ No newline at end of file diff --git a/corpus/nodes.txt b/corpus/nodes.txt new file mode 100644 index 0000000..250e0e3 --- /dev/null +++ b/corpus/nodes.txt @@ -0,0 +1,97 @@ +/** + * Copyright 2018 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TransferrableNode } from '../transfer/TransferrableNodes'; +import { RenderableElement } from './RenderableElement'; +import { TransferrableKeys } from '../transfer/TransferrableKeys'; +import { getString } from './strings'; +import { NodeType } from '../worker-thread/dom/Node'; + +let NODES: Map; +let BASE_ELEMENT: HTMLElement; + +export function prepare(baseElement: Element): void { + NODES = new Map([[1, baseElement as RenderableElement], [2, baseElement as RenderableElement]]); + BASE_ELEMENT = baseElement as HTMLElement; +} + +export function isTextNode(node: Node | TransferrableNode): boolean { + return ('nodeType' in node ? node.nodeType : node[TransferrableKeys.nodeType]) === NodeType.TEXT_NODE; +} + +/** + * Create a real DOM Node from a skeleton Object (`{ nodeType, nodeName, attributes, children, data }`) + * @example Text node + * createNode({ nodeType:3, data:'foo' }) + * @example Element node + * createNode({ nodeType:1, nodeName:'div', attributes:[{ name:'a', value:'b' }], childNodes:[ ... ] }) + */ +export function createNode(skeleton: TransferrableNode): RenderableElement { + if (isTextNode(skeleton)) { + const node = document.createTextNode(getString(skeleton[TransferrableKeys.textContent] as number)); + storeNode(node, skeleton[TransferrableKeys._index_]); + return node as RenderableElement; + } + + const namespace: string | undefined = + skeleton[TransferrableKeys.namespaceURI] !== undefined ? getString(skeleton[TransferrableKeys.namespaceURI] as number) : undefined; + const node: HTMLElement | SVGElement = namespace + ? (document.createElementNS(namespace, getString(skeleton[TransferrableKeys.nodeName])) as SVGElement) + : document.createElement(getString(skeleton[TransferrableKeys.nodeName])); + // TODO(KB): Restore Properties + // skeleton.properties.forEach(property => { + // node[`${property.name}`] = property.value; + // }); + // ((skeleton as TransferrableElement)[TransferrableKeys.childNodes] || []).forEach(childNode => { + // if (childNode[TransferrableKeys.transferred] === NumericBoolean.FALSE) { + // node.appendChild(createNode(childNode as TransferrableNode)); + // } + // }); + + storeNode(node, skeleton[TransferrableKeys._index_]); + return node as RenderableElement; +} + +/** + * Returns the real DOM Element corresponding to a serialized Element object. + * @param id + * @return + */ +export function getNode(id: number): RenderableElement { + const node = NODES.get(id); + + if (node && node.nodeName === 'BODY') { + // If the node requested is the "BODY" + // Then we return the base node this specific comes from. + // This encapsulates each node. + return BASE_ELEMENT as RenderableElement; + } + return node as RenderableElement; +} + +/** + * Establish link between DOM `node` and worker-generated identifier `id`. + * + * These _shouldn't_ collide between instances of since + * each element creates it's own pool on both sides of the worker + * communication bridge. + * @param node + * @param id + */ +export function storeNode(node: HTMLElement | SVGElement | Text, id: number): void { + (node as RenderableElement)._index_ = id; + NODES.set(id, node as RenderableElement); +} \ No newline at end of file diff --git a/corpus/parser.txt b/corpus/parser.txt new file mode 100644 index 0000000..1b792f6 --- /dev/null +++ b/corpus/parser.txt @@ -0,0 +1,7953 @@ +namespace ts { + const enum SignatureFlags { + None = 0, + Yield = 1 << 0, + Await = 1 << 1, + Type = 1 << 2, + IgnoreMissingOpenBrace = 1 << 4, + JSDoc = 1 << 5, + } + + // tslint:disable variable-name + let NodeConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; + let TokenConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; + let IdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; + let SourceFileConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; + // tslint:enable variable-name + + export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node { + if (kind === SyntaxKind.SourceFile) { + return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, pos, end); + } + else if (kind === SyntaxKind.Identifier) { + return new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, pos, end); + } + else if (!isNodeKind(kind)) { + return new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, pos, end); + } + else { + return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, pos, end); + } + } + + function visitNode(cbNode: (node: Node) => T, node: Node | undefined): T | undefined { + return node && cbNode(node); + } + + function visitNodes(cbNode: (node: Node) => T, cbNodes: ((node: NodeArray) => T | undefined) | undefined, nodes: NodeArray | undefined): T | undefined { + if (nodes) { + if (cbNodes) { + return cbNodes(nodes); + } + for (const node of nodes) { + const result = cbNode(node); + if (result) { + return result; + } + } + } + } + + /*@internal*/ + export function isJSDocLikeText(text: string, start: number) { + return text.charCodeAt(start + 1) === CharacterCodes.asterisk && + text.charCodeAt(start + 2) === CharacterCodes.asterisk && + text.charCodeAt(start + 3) !== CharacterCodes.slash; + } + + /** + * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes + * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise, + * embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns + * a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. + * + * @param node - a given node to visit its children + * @param cbNode - a callback to be invoked for all child nodes + * @param cbNodes - a callback to be invoked for embedded array + * + * @remarks - `forEachChild` must visit the children of a node in the order + * that they appear in the source code. The language service depends on this property to locate nodes by position. + */ + export function forEachChild(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + if (!node || node.kind <= SyntaxKind.LastToken) { + return; + } + switch (node.kind) { + case SyntaxKind.QualifiedName: + return visitNode(cbNode, (node).left) || + visitNode(cbNode, (node).right); + case SyntaxKind.TypeParameter: + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).constraint) || + visitNode(cbNode, (node).default) || + visitNode(cbNode, (node).expression); + case SyntaxKind.ShorthandPropertyAssignment: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).equalsToken) || + visitNode(cbNode, (node).objectAssignmentInitializer); + case SyntaxKind.SpreadAssignment: + return visitNode(cbNode, (node).expression); + case SyntaxKind.Parameter: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).dotDotDotToken) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.PropertyDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).exclamationToken) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.PropertySignature: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.PropertyAssignment: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.VariableDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).exclamationToken) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.BindingElement: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).dotDotDotToken) || + visitNode(cbNode, (node).propertyName) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNodes(cbNode, cbNodes, (node).typeParameters) || + visitNodes(cbNode, cbNodes, (node).parameters) || + visitNode(cbNode, (node).type); + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ArrowFunction: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).asteriskToken) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNodes(cbNode, cbNodes, (node).typeParameters) || + visitNodes(cbNode, cbNodes, (node).parameters) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).equalsGreaterThanToken) || + visitNode(cbNode, (node).body); + case SyntaxKind.TypeReference: + return visitNode(cbNode, (node).typeName) || + visitNodes(cbNode, cbNodes, (node).typeArguments); + case SyntaxKind.TypePredicate: + return visitNode(cbNode, (node).parameterName) || + visitNode(cbNode, (node).type); + case SyntaxKind.TypeQuery: + return visitNode(cbNode, (node).exprName); + case SyntaxKind.TypeLiteral: + return visitNodes(cbNode, cbNodes, (node).members); + case SyntaxKind.ArrayType: + return visitNode(cbNode, (node).elementType); + case SyntaxKind.TupleType: + return visitNodes(cbNode, cbNodes, (node).elementTypes); + case SyntaxKind.UnionType: + case SyntaxKind.IntersectionType: + return visitNodes(cbNode, cbNodes, (node).types); + case SyntaxKind.ConditionalType: + return visitNode(cbNode, (node).checkType) || + visitNode(cbNode, (node).extendsType) || + visitNode(cbNode, (node).trueType) || + visitNode(cbNode, (node).falseType); + case SyntaxKind.InferType: + return visitNode(cbNode, (node).typeParameter); + case SyntaxKind.ImportType: + return visitNode(cbNode, (node).argument) || + visitNode(cbNode, (node).qualifier) || + visitNodes(cbNode, cbNodes, (node).typeArguments); + case SyntaxKind.ParenthesizedType: + case SyntaxKind.TypeOperator: + return visitNode(cbNode, (node).type); + case SyntaxKind.IndexedAccessType: + return visitNode(cbNode, (node).objectType) || + visitNode(cbNode, (node).indexType); + case SyntaxKind.MappedType: + return visitNode(cbNode, (node).readonlyToken) || + visitNode(cbNode, (node).typeParameter) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).type); + case SyntaxKind.LiteralType: + return visitNode(cbNode, (node).literal); + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + return visitNodes(cbNode, cbNodes, (node).elements); + case SyntaxKind.ArrayLiteralExpression: + return visitNodes(cbNode, cbNodes, (node).elements); + case SyntaxKind.ObjectLiteralExpression: + return visitNodes(cbNode, cbNodes, (node).properties); + case SyntaxKind.PropertyAccessExpression: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).name); + case SyntaxKind.ElementAccessExpression: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).argumentExpression); + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + return visitNode(cbNode, (node).expression) || + visitNodes(cbNode, cbNodes, (node).typeArguments) || + visitNodes(cbNode, cbNodes, (node).arguments); + case SyntaxKind.TaggedTemplateExpression: + return visitNode(cbNode, (node).tag) || + visitNodes(cbNode, cbNodes, (node).typeArguments) || + visitNode(cbNode, (node).template); + case SyntaxKind.TypeAssertionExpression: + return visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).expression); + case SyntaxKind.ParenthesizedExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.DeleteExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.TypeOfExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.VoidExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.PrefixUnaryExpression: + return visitNode(cbNode, (node).operand); + case SyntaxKind.YieldExpression: + return visitNode(cbNode, (node).asteriskToken) || + visitNode(cbNode, (node).expression); + case SyntaxKind.AwaitExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.PostfixUnaryExpression: + return visitNode(cbNode, (node).operand); + case SyntaxKind.BinaryExpression: + return visitNode(cbNode, (node).left) || + visitNode(cbNode, (node).operatorToken) || + visitNode(cbNode, (node).right); + case SyntaxKind.AsExpression: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).type); + case SyntaxKind.NonNullExpression: + return visitNode(cbNode, (node).expression); + case SyntaxKind.MetaProperty: + return visitNode(cbNode, (node).name); + case SyntaxKind.ConditionalExpression: + return visitNode(cbNode, (node).condition) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).whenTrue) || + visitNode(cbNode, (node).colonToken) || + visitNode(cbNode, (node).whenFalse); + case SyntaxKind.SpreadElement: + return visitNode(cbNode, (node).expression); + case SyntaxKind.Block: + case SyntaxKind.ModuleBlock: + return visitNodes(cbNode, cbNodes, (node).statements); + case SyntaxKind.SourceFile: + return visitNodes(cbNode, cbNodes, (node).statements) || + visitNode(cbNode, (node).endOfFileToken); + case SyntaxKind.VariableStatement: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).declarationList); + case SyntaxKind.VariableDeclarationList: + return visitNodes(cbNode, cbNodes, (node).declarations); + case SyntaxKind.ExpressionStatement: + return visitNode(cbNode, (node).expression); + case SyntaxKind.IfStatement: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).thenStatement) || + visitNode(cbNode, (node).elseStatement); + case SyntaxKind.DoStatement: + return visitNode(cbNode, (node).statement) || + visitNode(cbNode, (node).expression); + case SyntaxKind.WhileStatement: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ForStatement: + return visitNode(cbNode, (node).initializer) || + visitNode(cbNode, (node).condition) || + visitNode(cbNode, (node).incrementor) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ForInStatement: + return visitNode(cbNode, (node).initializer) || + visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ForOfStatement: + return visitNode(cbNode, (node).awaitModifier) || + visitNode(cbNode, (node).initializer) || + visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ContinueStatement: + case SyntaxKind.BreakStatement: + return visitNode(cbNode, (node).label); + case SyntaxKind.ReturnStatement: + return visitNode(cbNode, (node).expression); + case SyntaxKind.WithStatement: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); + case SyntaxKind.SwitchStatement: + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).caseBlock); + case SyntaxKind.CaseBlock: + return visitNodes(cbNode, cbNodes, (node).clauses); + case SyntaxKind.CaseClause: + return visitNode(cbNode, (node).expression) || + visitNodes(cbNode, cbNodes, (node).statements); + case SyntaxKind.DefaultClause: + return visitNodes(cbNode, cbNodes, (node).statements); + case SyntaxKind.LabeledStatement: + return visitNode(cbNode, (node).label) || + visitNode(cbNode, (node).statement); + case SyntaxKind.ThrowStatement: + return visitNode(cbNode, (node).expression); + case SyntaxKind.TryStatement: + return visitNode(cbNode, (node).tryBlock) || + visitNode(cbNode, (node).catchClause) || + visitNode(cbNode, (node).finallyBlock); + case SyntaxKind.CatchClause: + return visitNode(cbNode, (node).variableDeclaration) || + visitNode(cbNode, (node).block); + case SyntaxKind.Decorator: + return visitNode(cbNode, (node).expression); + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNodes(cbNode, cbNodes, (node).typeParameters) || + visitNodes(cbNode, cbNodes, (node).heritageClauses) || + visitNodes(cbNode, cbNodes, (node).members); + case SyntaxKind.InterfaceDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNodes(cbNode, cbNodes, (node).typeParameters) || + visitNodes(cbNode, cbNodes, (node).heritageClauses) || + visitNodes(cbNode, cbNodes, (node).members); + case SyntaxKind.TypeAliasDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNodes(cbNode, cbNodes, (node).typeParameters) || + visitNode(cbNode, (node).type); + case SyntaxKind.EnumDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNodes(cbNode, cbNodes, (node).members); + case SyntaxKind.EnumMember: + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.ModuleDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).body); + case SyntaxKind.ImportEqualsDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).moduleReference); + case SyntaxKind.ImportDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).importClause) || + visitNode(cbNode, (node).moduleSpecifier); + case SyntaxKind.ImportClause: + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).namedBindings); + case SyntaxKind.NamespaceExportDeclaration: + return visitNode(cbNode, (node).name); + + case SyntaxKind.NamespaceImport: + return visitNode(cbNode, (node).name); + case SyntaxKind.NamedImports: + case SyntaxKind.NamedExports: + return visitNodes(cbNode, cbNodes, (node).elements); + case SyntaxKind.ExportDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).exportClause) || + visitNode(cbNode, (node).moduleSpecifier); + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ExportSpecifier: + return visitNode(cbNode, (node).propertyName) || + visitNode(cbNode, (node).name); + case SyntaxKind.ExportAssignment: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, (node).expression); + case SyntaxKind.TemplateExpression: + return visitNode(cbNode, (node).head) || visitNodes(cbNode, cbNodes, (node).templateSpans); + case SyntaxKind.TemplateSpan: + return visitNode(cbNode, (node).expression) || visitNode(cbNode, (node).literal); + case SyntaxKind.ComputedPropertyName: + return visitNode(cbNode, (node).expression); + case SyntaxKind.HeritageClause: + return visitNodes(cbNode, cbNodes, (node).types); + case SyntaxKind.ExpressionWithTypeArguments: + return visitNode(cbNode, (node).expression) || + visitNodes(cbNode, cbNodes, (node).typeArguments); + case SyntaxKind.ExternalModuleReference: + return visitNode(cbNode, (node).expression); + case SyntaxKind.MissingDeclaration: + return visitNodes(cbNode, cbNodes, node.decorators); + case SyntaxKind.CommaListExpression: + return visitNodes(cbNode, cbNodes, (node).elements); + + case SyntaxKind.JsxElement: + return visitNode(cbNode, (node).openingElement) || + visitNodes(cbNode, cbNodes, (node).children) || + visitNode(cbNode, (node).closingElement); + case SyntaxKind.JsxFragment: + return visitNode(cbNode, (node).openingFragment) || + visitNodes(cbNode, cbNodes, (node).children) || + visitNode(cbNode, (node).closingFragment); + case SyntaxKind.JsxSelfClosingElement: + case SyntaxKind.JsxOpeningElement: + return visitNode(cbNode, (node).tagName) || + visitNodes(cbNode, cbNodes, (node).typeArguments) || + visitNode(cbNode, (node).attributes); + case SyntaxKind.JsxAttributes: + return visitNodes(cbNode, cbNodes, (node).properties); + case SyntaxKind.JsxAttribute: + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).initializer); + case SyntaxKind.JsxSpreadAttribute: + return visitNode(cbNode, (node).expression); + case SyntaxKind.JsxExpression: + return visitNode(cbNode, (node as JsxExpression).dotDotDotToken) || + visitNode(cbNode, (node as JsxExpression).expression); + case SyntaxKind.JsxClosingElement: + return visitNode(cbNode, (node).tagName); + + case SyntaxKind.OptionalType: + case SyntaxKind.RestType: + case SyntaxKind.JSDocTypeExpression: + case SyntaxKind.JSDocNonNullableType: + case SyntaxKind.JSDocNullableType: + case SyntaxKind.JSDocOptionalType: + case SyntaxKind.JSDocVariadicType: + return visitNode(cbNode, (node).type); + case SyntaxKind.JSDocFunctionType: + return visitNodes(cbNode, cbNodes, (node).parameters) || + visitNode(cbNode, (node).type); + case SyntaxKind.JSDocComment: + return visitNodes(cbNode, cbNodes, (node).tags); + case SyntaxKind.JSDocParameterTag: + case SyntaxKind.JSDocPropertyTag: + if ((node as JSDocPropertyLikeTag).isNameFirst) { + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).typeExpression); + } + else { + return visitNode(cbNode, (node).typeExpression) || + visitNode(cbNode, (node).name); + } + case SyntaxKind.JSDocReturnTag: + return visitNode(cbNode, (node).typeExpression); + case SyntaxKind.JSDocTypeTag: + return visitNode(cbNode, (node).typeExpression); + case SyntaxKind.JSDocAugmentsTag: + return visitNode(cbNode, (node).class); + case SyntaxKind.JSDocTemplateTag: + return visitNode(cbNode, (node).constraint) || visitNodes(cbNode, cbNodes, (node).typeParameters); + case SyntaxKind.JSDocTypedefTag: + if ((node as JSDocTypedefTag).typeExpression && + (node as JSDocTypedefTag).typeExpression!.kind === SyntaxKind.JSDocTypeExpression) { + return visitNode(cbNode, (node).typeExpression) || + visitNode(cbNode, (node).fullName); + } + else { + return visitNode(cbNode, (node).fullName) || + visitNode(cbNode, (node).typeExpression); + } + case SyntaxKind.JSDocCallbackTag: + return visitNode(cbNode, (node as JSDocCallbackTag).fullName) || + visitNode(cbNode, (node as JSDocCallbackTag).typeExpression); + case SyntaxKind.JSDocThisTag: + return visitNode(cbNode, (node as JSDocThisTag).typeExpression); + case SyntaxKind.JSDocEnumTag: + return visitNode(cbNode, (node as JSDocEnumTag).typeExpression); + case SyntaxKind.JSDocSignature: + return visitNodes(cbNode, cbNodes, node.decorators) || + visitNodes(cbNode, cbNodes, node.modifiers) || + forEach((node).typeParameters, cbNode) || + forEach((node).parameters, cbNode) || + visitNode(cbNode, (node).type); + case SyntaxKind.JSDocTypeLiteral: + if ((node as JSDocTypeLiteral).jsDocPropertyTags) { + for (const tag of (node as JSDocTypeLiteral).jsDocPropertyTags!) { + visitNode(cbNode, tag); + } + } + return; + case SyntaxKind.PartiallyEmittedExpression: + return visitNode(cbNode, (node).expression); + } + } + + export function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false, scriptKind?: ScriptKind): SourceFile { + performance.mark("beforeParse"); + let result: SourceFile; + if (languageVersion === ScriptTarget.JSON) { + result = Parser.parseJsonText(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes); + } + else { + result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind); + } + performance.mark("afterParse"); + performance.measure("Parse", "beforeParse", "afterParse"); + return result; + } + + export function parseIsolatedEntityName(text: string, languageVersion: ScriptTarget): EntityName | undefined { + return Parser.parseIsolatedEntityName(text, languageVersion); + } + + /** + * Parse json text into SyntaxTree and return node and parse errors if any + * @param fileName + * @param sourceText + */ + export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile { + return Parser.parseJsonText(fileName, sourceText); + } + + // See also `isExternalOrCommonJsModule` in utilities.ts + export function isExternalModule(file: SourceFile): boolean { + return file.externalModuleIndicator !== undefined; + } + + // Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter + // indicates what changed between the 'text' that this SourceFile has and the 'newText'. + // The SourceFile will be created with the compiler attempting to reuse as many nodes from + // this file as possible. + // + // Note: this function mutates nodes from this SourceFile. That means any existing nodes + // from this SourceFile that are being held onto may change as a result (including + // becoming detached from any SourceFile). It is recommended that this SourceFile not + // be used once 'update' is called on it. + export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks = false): SourceFile { + const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks); + // Because new source file node is created, it may not have the flag PossiblyContainDynamicImport. This is the case if there is no new edit to add dynamic import. + // We will manually port the flag to the new source file. + newSourceFile.flags |= (sourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags); + return newSourceFile; + } + + /* @internal */ + export function parseIsolatedJSDocComment(content: string, start?: number, length?: number) { + const result = Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length); + if (result && result.jsDoc) { + // because the jsDocComment was parsed out of the source file, it might + // not be covered by the fixupParentReferences. + Parser.fixupParentReferences(result.jsDoc); + } + + return result; + } + + /* @internal */ + // Exposed only for testing. + export function parseJSDocTypeExpressionForTests(content: string, start?: number, length?: number) { + return Parser.JSDocParser.parseJSDocTypeExpressionForTests(content, start, length); + } + + // Implement the parser as a singleton module. We do this for perf reasons because creating + // parser instances can actually be expensive enough to impact us on projects with many source + // files. + namespace Parser { + // Share a single scanner across all calls to parse a source file. This helps speed things + // up by avoiding the cost of creating/compiling scanners over and over again. + const scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true); + const disallowInAndDecoratorContext = NodeFlags.DisallowInContext | NodeFlags.DecoratorContext; + + // capture constructors in 'initializeState' to avoid null checks + // tslint:disable variable-name + let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + // tslint:enable variable-name + + let sourceFile: SourceFile; + let parseDiagnostics: DiagnosticWithLocation[]; + let syntaxCursor: IncrementalParser.SyntaxCursor | undefined; + + let currentToken: SyntaxKind; + let sourceText: string; + let nodeCount: number; + let identifiers: Map; + let identifierCount: number; + + let parsingContext: ParsingContext; + + // Flags that dictate what parsing context we're in. For example: + // Whether or not we are in strict parsing mode. All that changes in strict parsing mode is + // that some tokens that would be considered identifiers may be considered keywords. + // + // When adding more parser context flags, consider which is the more common case that the + // flag will be in. This should be the 'false' state for that flag. The reason for this is + // that we don't store data in our nodes unless the value is in the *non-default* state. So, + // for example, more often than code 'allows-in' (or doesn't 'disallow-in'). We opt for + // 'disallow-in' set to 'false'. Otherwise, if we had 'allowsIn' set to 'true', then almost + // all nodes would need extra state on them to store this info. + // + // Note: 'allowIn' and 'allowYield' track 1:1 with the [in] and [yield] concepts in the ES6 + // grammar specification. + // + // An important thing about these context concepts. By default they are effectively inherited + // while parsing through every grammar production. i.e. if you don't change them, then when + // you parse a sub-production, it will have the same context values as the parent production. + // This is great most of the time. After all, consider all the 'expression' grammar productions + // and how nearly all of them pass along the 'in' and 'yield' context values: + // + // EqualityExpression[In, Yield] : + // RelationalExpression[?In, ?Yield] + // EqualityExpression[?In, ?Yield] == RelationalExpression[?In, ?Yield] + // EqualityExpression[?In, ?Yield] != RelationalExpression[?In, ?Yield] + // EqualityExpression[?In, ?Yield] === RelationalExpression[?In, ?Yield] + // EqualityExpression[?In, ?Yield] !== RelationalExpression[?In, ?Yield] + // + // Where you have to be careful is then understanding what the points are in the grammar + // where the values are *not* passed along. For example: + // + // SingleNameBinding[Yield,GeneratorParameter] + // [+GeneratorParameter]BindingIdentifier[Yield] Initializer[In]opt + // [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt + // + // Here this is saying that if the GeneratorParameter context flag is set, that we should + // explicitly set the 'yield' context flag to false before calling into the BindingIdentifier + // and we should explicitly unset the 'yield' context flag before calling into the Initializer. + // production. Conversely, if the GeneratorParameter context flag is not set, then we + // should leave the 'yield' context flag alone. + // + // Getting this all correct is tricky and requires careful reading of the grammar to + // understand when these values should be changed versus when they should be inherited. + // + // Note: it should not be necessary to save/restore these flags during speculative/lookahead + // parsing. These context flags are naturally stored and restored through normal recursive + // descent parsing and unwinding. + let contextFlags: NodeFlags; + + // Whether or not we've had a parse error since creating the last AST node. If we have + // encountered an error, it will be stored on the next AST node we create. Parse errors + // can be broken down into three categories: + // + // 1) An error that occurred during scanning. For example, an unterminated literal, or a + // character that was completely not understood. + // + // 2) A token was expected, but was not present. This type of error is commonly produced + // by the 'parseExpected' function. + // + // 3) A token was present that no parsing function was able to consume. This type of error + // only occurs in the 'abortParsingListOrMoveToNextToken' function when the parser + // decides to skip the token. + // + // In all of these cases, we want to mark the next node as having had an error before it. + // With this mark, we can know in incremental settings if this node can be reused, or if + // we have to reparse it. If we don't keep this information around, we may just reuse the + // node. in that event we would then not produce the same errors as we did before, causing + // significant confusion problems. + // + // Note: it is necessary that this value be saved/restored during speculative/lookahead + // parsing. During lookahead parsing, we will often create a node. That node will have + // this value attached, and then this value will be set back to 'false'. If we decide to + // rewind, we must get back to the same value we had prior to the lookahead. + // + // Note: any errors at the end of the file that do not precede a regular node, should get + // attached to the EOF token. + let parseErrorBeforeNextFinishedNode = false; + + export function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: IncrementalParser.SyntaxCursor | undefined, setParentNodes = false, scriptKind?: ScriptKind): SourceFile { + scriptKind = ensureScriptKind(fileName, scriptKind); + if (scriptKind === ScriptKind.JSON) { + const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes); + convertToObjectWorker(result, result.parseDiagnostics, /*returnValue*/ false, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined); + result.typeReferenceDirectives = emptyArray; + result.amdDependencies = emptyArray; + return result; + } + + initializeState(sourceText, languageVersion, syntaxCursor, scriptKind); + + const result = parseSourceFileWorker(fileName, languageVersion, setParentNodes, scriptKind); + + clearState(); + + return result; + } + + export function parseIsolatedEntityName(content: string, languageVersion: ScriptTarget): EntityName | undefined { + // Choice of `isDeclarationFile` should be arbitrary + initializeState(content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS); + // Prime the scanner. + nextToken(); + const entityName = parseEntityName(/*allowReservedWords*/ true); + const isInvalid = token() === SyntaxKind.EndOfFileToken && !parseDiagnostics.length; + clearState(); + return isInvalid ? entityName : undefined; + } + + export function parseJsonText(fileName: string, sourceText: string, languageVersion: ScriptTarget = ScriptTarget.ES2015, syntaxCursor?: IncrementalParser.SyntaxCursor, setParentNodes?: boolean): JsonSourceFile { + initializeState(sourceText, languageVersion, syntaxCursor, ScriptKind.JSON); + // Set source file so that errors will be reported with this file name + sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON, /*isDeclaration*/ false); + sourceFile.flags = contextFlags; + + // Prime the scanner. + nextToken(); + const pos = getNodePos(); + if (token() === SyntaxKind.EndOfFileToken) { + sourceFile.statements = createNodeArray([], pos, pos); + sourceFile.endOfFileToken = parseTokenNode(); + } + else { + const statement = createNode(SyntaxKind.ExpressionStatement) as JsonObjectExpressionStatement; + switch (token()) { + case SyntaxKind.OpenBracketToken: + statement.expression = parseArrayLiteralExpression(); + break; + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + case SyntaxKind.NullKeyword: + statement.expression = parseTokenNode(); + break; + case SyntaxKind.MinusToken: + if (lookAhead(() => nextToken() === SyntaxKind.NumericLiteral && nextToken() !== SyntaxKind.ColonToken)) { + statement.expression = parsePrefixUnaryExpression() as JsonMinusNumericLiteral; + } + else { + statement.expression = parseObjectLiteralExpression(); + } + break; + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + if (lookAhead(() => nextToken() !== SyntaxKind.ColonToken)) { + statement.expression = parseLiteralNode() as StringLiteral | NumericLiteral; + break; + } + // falls through + default: + statement.expression = parseObjectLiteralExpression(); + break; + } + finishNode(statement); + sourceFile.statements = createNodeArray([statement], pos); + sourceFile.endOfFileToken = parseExpectedToken(SyntaxKind.EndOfFileToken, Diagnostics.Unexpected_token); + } + + if (setParentNodes) { + fixupParentReferences(sourceFile); + } + + sourceFile.parseDiagnostics = parseDiagnostics; + const result = sourceFile as JsonSourceFile; + clearState(); + return result; + } + + function getLanguageVariant(scriptKind: ScriptKind) { + // .tsx and .jsx files are treated as jsx language variant. + return scriptKind === ScriptKind.TSX || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSON ? LanguageVariant.JSX : LanguageVariant.Standard; + } + + function initializeState(_sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, scriptKind: ScriptKind) { + NodeConstructor = objectAllocator.getNodeConstructor(); + TokenConstructor = objectAllocator.getTokenConstructor(); + IdentifierConstructor = objectAllocator.getIdentifierConstructor(); + SourceFileConstructor = objectAllocator.getSourceFileConstructor(); + + sourceText = _sourceText; + syntaxCursor = _syntaxCursor; + + parseDiagnostics = []; + parsingContext = 0; + identifiers = createMap(); + identifierCount = 0; + nodeCount = 0; + + switch (scriptKind) { + case ScriptKind.JS: + case ScriptKind.JSX: + contextFlags = NodeFlags.JavaScriptFile; + break; + case ScriptKind.JSON: + contextFlags = NodeFlags.JavaScriptFile | NodeFlags.JsonFile; + break; + default: + contextFlags = NodeFlags.None; + break; + } + parseErrorBeforeNextFinishedNode = false; + + // Initialize and prime the scanner before parsing the source elements. + scanner.setText(sourceText); + scanner.setOnError(scanError); + scanner.setScriptTarget(languageVersion); + scanner.setLanguageVariant(getLanguageVariant(scriptKind)); + } + + function clearState() { + // Clear out the text the scanner is pointing at, so it doesn't keep anything alive unnecessarily. + scanner.setText(""); + scanner.setOnError(undefined); + + // Clear any data. We don't want to accidentally hold onto it for too long. + parseDiagnostics = undefined!; + sourceFile = undefined!; + identifiers = undefined!; + syntaxCursor = undefined; + sourceText = undefined!; + } + + function parseSourceFileWorker(fileName: string, languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind): SourceFile { + const isDeclarationFile = isDeclarationFileName(fileName); + if (isDeclarationFile) { + contextFlags |= NodeFlags.Ambient; + } + + sourceFile = createSourceFile(fileName, languageVersion, scriptKind, isDeclarationFile); + sourceFile.flags = contextFlags; + + // Prime the scanner. + nextToken(); + // A member of ReadonlyArray isn't assignable to a member of T[] (and prevents a direct cast) - but this is where we set up those members so they can be readonly in the future + processCommentPragmas(sourceFile as {} as PragmaContext, sourceText); + processPragmasIntoFields(sourceFile as {} as PragmaContext, reportPragmaDiagnostic); + + sourceFile.statements = parseList(ParsingContext.SourceElements, parseStatement); + Debug.assert(token() === SyntaxKind.EndOfFileToken); + sourceFile.endOfFileToken = addJSDocComment(parseTokenNode()); + + setExternalModuleIndicator(sourceFile); + + sourceFile.nodeCount = nodeCount; + sourceFile.identifierCount = identifierCount; + sourceFile.identifiers = identifiers; + sourceFile.parseDiagnostics = parseDiagnostics; + + if (setParentNodes) { + fixupParentReferences(sourceFile); + } + + return sourceFile; + + function reportPragmaDiagnostic(pos: number, end: number, diagnostic: DiagnosticMessage) { + parseDiagnostics.push(createFileDiagnostic(sourceFile, pos, end, diagnostic)); + } + } + + function addJSDocComment(node: T): T { + Debug.assert(!node.jsDoc); // Should only be called once per node + const jsDoc = mapDefined(getJSDocCommentRanges(node, sourceFile.text), comment => JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos)); + if (jsDoc.length) node.jsDoc = jsDoc; + return node; + } + + export function fixupParentReferences(rootNode: Node) { + // normally parent references are set during binding. However, for clients that only need + // a syntax tree, and no semantic features, then the binding process is an unnecessary + // overhead. This functions allows us to set all the parents, without all the expense of + // binding. + + let parent: Node = rootNode; + forEachChild(rootNode, visitNode); + return; + + function visitNode(n: Node): void { + // walk down setting parents that differ from the parent we think it should be. This + // allows us to quickly bail out of setting parents for subtrees during incremental + // parsing + if (n.parent !== parent) { + n.parent = parent; + + const saveParent = parent; + parent = n; + forEachChild(n, visitNode); + if (hasJSDocNodes(n)) { + for (const jsDoc of n.jsDoc!) { + jsDoc.parent = n; + parent = jsDoc; + forEachChild(jsDoc, visitNode); + } + } + parent = saveParent; + } + } + } + + function createSourceFile(fileName: string, languageVersion: ScriptTarget, scriptKind: ScriptKind, isDeclarationFile: boolean): SourceFile { + // code from createNode is inlined here so createNode won't have to deal with special case of creating source files + // this is quite rare comparing to other nodes and createNode should be as fast as possible + const sourceFile = new SourceFileConstructor(SyntaxKind.SourceFile, /*pos*/ 0, /* end */ sourceText.length); + nodeCount++; + + sourceFile.text = sourceText; + sourceFile.bindDiagnostics = []; + sourceFile.bindSuggestionDiagnostics = undefined; + sourceFile.languageVersion = languageVersion; + sourceFile.fileName = normalizePath(fileName); + sourceFile.languageVariant = getLanguageVariant(scriptKind); + sourceFile.isDeclarationFile = isDeclarationFile; + sourceFile.scriptKind = scriptKind; + + return sourceFile; + } + + function setContextFlag(val: boolean, flag: NodeFlags) { + if (val) { + contextFlags |= flag; + } + else { + contextFlags &= ~flag; + } + } + + function setDisallowInContext(val: boolean) { + setContextFlag(val, NodeFlags.DisallowInContext); + } + + function setYieldContext(val: boolean) { + setContextFlag(val, NodeFlags.YieldContext); + } + + function setDecoratorContext(val: boolean) { + setContextFlag(val, NodeFlags.DecoratorContext); + } + + function setAwaitContext(val: boolean) { + setContextFlag(val, NodeFlags.AwaitContext); + } + + function doOutsideOfContext(context: NodeFlags, func: () => T): T { + // contextFlagsToClear will contain only the context flags that are + // currently set that we need to temporarily clear + // We don't just blindly reset to the previous flags to ensure + // that we do not mutate cached flags for the incremental + // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and + // HasAggregatedChildData). + const contextFlagsToClear = context & contextFlags; + if (contextFlagsToClear) { + // clear the requested context flags + setContextFlag(/*val*/ false, contextFlagsToClear); + const result = func(); + // restore the context flags we just cleared + setContextFlag(/*val*/ true, contextFlagsToClear); + return result; + } + + // no need to do anything special as we are not in any of the requested contexts + return func(); + } + + function doInsideOfContext(context: NodeFlags, func: () => T): T { + // contextFlagsToSet will contain only the context flags that + // are not currently set that we need to temporarily enable. + // We don't just blindly reset to the previous flags to ensure + // that we do not mutate cached flags for the incremental + // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and + // HasAggregatedChildData). + const contextFlagsToSet = context & ~contextFlags; + if (contextFlagsToSet) { + // set the requested context flags + setContextFlag(/*val*/ true, contextFlagsToSet); + const result = func(); + // reset the context flags we just set + setContextFlag(/*val*/ false, contextFlagsToSet); + return result; + } + + // no need to do anything special as we are already in all of the requested contexts + return func(); + } + + function allowInAnd(func: () => T): T { + return doOutsideOfContext(NodeFlags.DisallowInContext, func); + } + + function disallowInAnd(func: () => T): T { + return doInsideOfContext(NodeFlags.DisallowInContext, func); + } + + function doInYieldContext(func: () => T): T { + return doInsideOfContext(NodeFlags.YieldContext, func); + } + + function doInDecoratorContext(func: () => T): T { + return doInsideOfContext(NodeFlags.DecoratorContext, func); + } + + function doInAwaitContext(func: () => T): T { + return doInsideOfContext(NodeFlags.AwaitContext, func); + } + + function doOutsideOfAwaitContext(func: () => T): T { + return doOutsideOfContext(NodeFlags.AwaitContext, func); + } + + function doInYieldAndAwaitContext(func: () => T): T { + return doInsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func); + } + + function inContext(flags: NodeFlags) { + return (contextFlags & flags) !== 0; + } + + function inYieldContext() { + return inContext(NodeFlags.YieldContext); + } + + function inDisallowInContext() { + return inContext(NodeFlags.DisallowInContext); + } + + function inDecoratorContext() { + return inContext(NodeFlags.DecoratorContext); + } + + function inAwaitContext() { + return inContext(NodeFlags.AwaitContext); + } + + function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): void { + parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), message, arg0); + } + + function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, arg0?: any): void { + // Don't report another error if it would just be at the same position as the last error. + const lastError = lastOrUndefined(parseDiagnostics); + if (!lastError || start !== lastError.start) { + parseDiagnostics.push(createFileDiagnostic(sourceFile, start, length, message, arg0)); + } + + // Mark that we've encountered an error. We'll set an appropriate bit on the next + // node we finish so that it can't be reused incrementally. + parseErrorBeforeNextFinishedNode = true; + } + + function parseErrorAt(start: number, end: number, message: DiagnosticMessage, arg0?: any): void { + parseErrorAtPosition(start, end - start, message, arg0); + } + + function parseErrorAtRange(range: TextRange, message: DiagnosticMessage, arg0?: any): void { + parseErrorAt(range.pos, range.end, message, arg0); + } + + function scanError(message: DiagnosticMessage, length: number): void { + parseErrorAtPosition(scanner.getTextPos(), length, message); + } + + function getNodePos(): number { + return scanner.getStartPos(); + } + + // Use this function to access the current token instead of reading the currentToken + // variable. Since function results aren't narrowed in control flow analysis, this ensures + // that the type checker doesn't make wrong assumptions about the type of the current + // token (e.g. a call to nextToken() changes the current token but the checker doesn't + // reason about this side effect). Mainstream VMs inline simple functions like this, so + // there is no performance penalty. + function token(): SyntaxKind { + return currentToken; + } + + function nextToken(): SyntaxKind { + return currentToken = scanner.scan(); + } + + function reScanGreaterToken(): SyntaxKind { + return currentToken = scanner.reScanGreaterToken(); + } + + function reScanSlashToken(): SyntaxKind { + return currentToken = scanner.reScanSlashToken(); + } + + function reScanTemplateToken(): SyntaxKind { + return currentToken = scanner.reScanTemplateToken(); + } + + function scanJsxIdentifier(): SyntaxKind { + return currentToken = scanner.scanJsxIdentifier(); + } + + function scanJsxText(): SyntaxKind { + return currentToken = scanner.scanJsxToken(); + } + + function scanJsxAttributeValue(): SyntaxKind { + return currentToken = scanner.scanJsxAttributeValue(); + } + + function speculationHelper(callback: () => T, isLookAhead: boolean): T { + // Keep track of the state we'll need to rollback to if lookahead fails (or if the + // caller asked us to always reset our state). + const saveToken = currentToken; + const saveParseDiagnosticsLength = parseDiagnostics.length; + const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; + + // Note: it is not actually necessary to save/restore the context flags here. That's + // because the saving/restoring of these flags happens naturally through the recursive + // descent nature of our parser. However, we still store this here just so we can + // assert that invariant holds. + const saveContextFlags = contextFlags; + + // If we're only looking ahead, then tell the scanner to only lookahead as well. + // Otherwise, if we're actually speculatively parsing, then tell the scanner to do the + // same. + const result = isLookAhead + ? scanner.lookAhead(callback) + : scanner.tryScan(callback); + + Debug.assert(saveContextFlags === contextFlags); + + // If our callback returned something 'falsy' or we're just looking ahead, + // then unconditionally restore us to where we were. + if (!result || isLookAhead) { + currentToken = saveToken; + parseDiagnostics.length = saveParseDiagnosticsLength; + parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode; + } + + return result; + } + + /** Invokes the provided callback then unconditionally restores the parser to the state it + * was in immediately prior to invoking the callback. The result of invoking the callback + * is returned from this function. + */ + function lookAhead(callback: () => T): T { + return speculationHelper(callback, /*isLookAhead*/ true); + } + + /** Invokes the provided callback. If the callback returns something falsy, then it restores + * the parser to the state it was in immediately prior to invoking the callback. If the + * callback returns something truthy, then the parser state is not rolled back. The result + * of invoking the callback is returned from this function. + */ + function tryParse(callback: () => T): T { + return speculationHelper(callback, /*isLookAhead*/ false); + } + + // Ignore strict mode flag because we will report an error in type checker instead. + function isIdentifier(): boolean { + if (token() === SyntaxKind.Identifier) { + return true; + } + + // If we have a 'yield' keyword, and we're in the [yield] context, then 'yield' is + // considered a keyword and is not an identifier. + if (token() === SyntaxKind.YieldKeyword && inYieldContext()) { + return false; + } + + // If we have a 'await' keyword, and we're in the [Await] context, then 'await' is + // considered a keyword and is not an identifier. + if (token() === SyntaxKind.AwaitKeyword && inAwaitContext()) { + return false; + } + + return token() > SyntaxKind.LastReservedWord; + } + + function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage, shouldAdvance = true): boolean { + if (token() === kind) { + if (shouldAdvance) { + nextToken(); + } + return true; + } + + // Report specific message if provided with one. Otherwise, report generic fallback message. + if (diagnosticMessage) { + parseErrorAtCurrentToken(diagnosticMessage); + } + else { + parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind)); + } + return false; + } + + function parseOptional(t: SyntaxKind): boolean { + if (token() === t) { + nextToken(); + return true; + } + return false; + } + + function parseOptionalToken(t: TKind): Token; + function parseOptionalToken(t: SyntaxKind): Node | undefined { + if (token() === t) { + return parseTokenNode(); + } + return undefined; + } + + function parseExpectedToken(t: TKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Token; + function parseExpectedToken(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Node { + return parseOptionalToken(t) || + createMissingNode(t, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics._0_expected, arg0 || tokenToString(t)); + } + + function parseTokenNode(): T { + const node = createNode(token()); + nextToken(); + return finishNode(node); + } + + function canParseSemicolon() { + // If there's a real semicolon, then we can always parse it out. + if (token() === SyntaxKind.SemicolonToken) { + return true; + } + + // We can parse out an optional semicolon in ASI cases in the following cases. + return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak(); + } + + function parseSemicolon(): boolean { + if (canParseSemicolon()) { + if (token() === SyntaxKind.SemicolonToken) { + // consume the semicolon if it was explicitly provided. + nextToken(); + } + + return true; + } + else { + return parseExpected(SyntaxKind.SemicolonToken); + } + } + + function createNode(kind: SyntaxKind, pos?: number): Node { + nodeCount++; + const p = pos! >= 0 ? pos! : scanner.getStartPos(); + return isNodeKind(kind) || kind === SyntaxKind.Unknown ? new NodeConstructor(kind, p, p) : + kind === SyntaxKind.Identifier ? new IdentifierConstructor(kind, p, p) : + new TokenConstructor(kind, p, p); + } + + function createNodeWithJSDoc(kind: SyntaxKind, pos?: number): Node { + const node = createNode(kind, pos); + if (scanner.getTokenFlags() & TokenFlags.PrecedingJSDocComment) { + addJSDocComment(node); + } + return node; + } + + function createNodeArray(elements: T[], pos: number, end?: number): NodeArray { + // Since the element list of a node array is typically created by starting with an empty array and + // repeatedly calling push(), the list may not have the optimal memory layout. We invoke slice() for + // small arrays (1 to 4 elements) to give the VM a chance to allocate an optimal representation. + const length = elements.length; + const array = >(length >= 1 && length <= 4 ? elements.slice() : elements); + array.pos = pos; + array.end = end === undefined ? scanner.getStartPos() : end; + return array; + } + + function finishNode(node: T, end?: number): T { + node.end = end === undefined ? scanner.getStartPos() : end; + + if (contextFlags) { + node.flags |= contextFlags; + } + + // Keep track on the node if we encountered an error while parsing it. If we did, then + // we cannot reuse the node incrementally. Once we've marked this node, clear out the + // flag so that we don't mark any subsequent nodes. + if (parseErrorBeforeNextFinishedNode) { + parseErrorBeforeNextFinishedNode = false; + node.flags |= NodeFlags.ThisNodeHasError; + } + + return node; + } + + function createMissingNode(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T { + if (reportAtCurrentPosition) { + parseErrorAtPosition(scanner.getStartPos(), 0, diagnosticMessage, arg0); + } + else if (diagnosticMessage) { + parseErrorAtCurrentToken(diagnosticMessage, arg0); + } + + const result = createNode(kind); + + if (kind === SyntaxKind.Identifier) { + (result as Identifier).escapedText = "" as __String; + } + else if (isLiteralKind(kind) || isTemplateLiteralKind(kind)) { + (result as LiteralLikeNode).text = ""; + } + + return finishNode(result) as T; + } + + function internIdentifier(text: string): string { + let identifier = identifiers.get(text); + if (identifier === undefined) { + identifiers.set(text, identifier = text); + } + return identifier; + } + + // An identifier that starts with two underscores has an extra underscore character prepended to it to avoid issues + // with magic property names like '__proto__'. The 'identifiers' object is used to share a single string instance for + // each identifier in order to reduce memory consumption. + function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage): Identifier { + identifierCount++; + if (isIdentifier) { + const node = createNode(SyntaxKind.Identifier); + + // Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker + if (token() !== SyntaxKind.Identifier) { + node.originalKeywordKind = token(); + } + node.escapedText = escapeLeadingUnderscores(internIdentifier(scanner.getTokenValue())); + nextToken(); + return finishNode(node); + } + + // Only for end of file because the error gets reported incorrectly on embedded script tags. + const reportAtCurrentPosition = token() === SyntaxKind.EndOfFileToken; + + return createMissingNode(SyntaxKind.Identifier, reportAtCurrentPosition, diagnosticMessage || Diagnostics.Identifier_expected); + } + + function parseIdentifier(diagnosticMessage?: DiagnosticMessage): Identifier { + return createIdentifier(isIdentifier(), diagnosticMessage); + } + + function parseIdentifierName(diagnosticMessage?: DiagnosticMessage): Identifier { + return createIdentifier(tokenIsIdentifierOrKeyword(token()), diagnosticMessage); + } + + function isLiteralPropertyName(): boolean { + return tokenIsIdentifierOrKeyword(token()) || + token() === SyntaxKind.StringLiteral || + token() === SyntaxKind.NumericLiteral; + } + + function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName { + if (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NumericLiteral) { + const node = parseLiteralNode(); + node.text = internIdentifier(node.text); + return node; + } + if (allowComputedPropertyNames && token() === SyntaxKind.OpenBracketToken) { + return parseComputedPropertyName(); + } + return parseIdentifierName(); + } + + function parsePropertyName(): PropertyName { + return parsePropertyNameWorker(/*allowComputedPropertyNames*/ true); + } + + function parseComputedPropertyName(): ComputedPropertyName { + // PropertyName [Yield]: + // LiteralPropertyName + // ComputedPropertyName[?Yield] + const node = createNode(SyntaxKind.ComputedPropertyName); + parseExpected(SyntaxKind.OpenBracketToken); + + // We parse any expression (including a comma expression). But the grammar + // says that only an assignment expression is allowed, so the grammar checker + // will error if it sees a comma expression. + node.expression = allowInAnd(parseExpression); + + parseExpected(SyntaxKind.CloseBracketToken); + return finishNode(node); + } + + function parseContextualModifier(t: SyntaxKind): boolean { + return token() === t && tryParse(nextTokenCanFollowModifier); + } + + function nextTokenIsOnSameLineAndCanFollowModifier() { + nextToken(); + if (scanner.hasPrecedingLineBreak()) { + return false; + } + return canFollowModifier(); + } + + function nextTokenCanFollowModifier() { + switch (token()) { + case SyntaxKind.ConstKeyword: + // 'const' is only a modifier if followed by 'enum'. + return nextToken() === SyntaxKind.EnumKeyword; + case SyntaxKind.ExportKeyword: + nextToken(); + if (token() === SyntaxKind.DefaultKeyword) { + return lookAhead(nextTokenCanFollowDefaultKeyword); + } + return token() !== SyntaxKind.AsteriskToken && token() !== SyntaxKind.AsKeyword && token() !== SyntaxKind.OpenBraceToken && canFollowModifier(); + case SyntaxKind.DefaultKeyword: + return nextTokenCanFollowDefaultKeyword(); + case SyntaxKind.StaticKeyword: + case SyntaxKind.GetKeyword: + case SyntaxKind.SetKeyword: + nextToken(); + return canFollowModifier(); + default: + return nextTokenIsOnSameLineAndCanFollowModifier(); + } + } + + function parseAnyContextualModifier(): boolean { + return isModifierKind(token()) && tryParse(nextTokenCanFollowModifier); + } + + function canFollowModifier(): boolean { + return token() === SyntaxKind.OpenBracketToken + || token() === SyntaxKind.OpenBraceToken + || token() === SyntaxKind.AsteriskToken + || token() === SyntaxKind.DotDotDotToken + || isLiteralPropertyName(); + } + + function nextTokenCanFollowDefaultKeyword(): boolean { + nextToken(); + return token() === SyntaxKind.ClassKeyword || token() === SyntaxKind.FunctionKeyword || + token() === SyntaxKind.InterfaceKeyword || + (token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsClassKeywordOnSameLine)) || + (token() === SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsFunctionKeywordOnSameLine)); + } + + // True if positioned at the start of a list element + function isListElement(parsingContext: ParsingContext, inErrorRecovery: boolean): boolean { + const node = currentNode(parsingContext); + if (node) { + return true; + } + + switch (parsingContext) { + case ParsingContext.SourceElements: + case ParsingContext.BlockStatements: + case ParsingContext.SwitchClauseStatements: + // If we're in error recovery, then we don't want to treat ';' as an empty statement. + // The problem is that ';' can show up in far too many contexts, and if we see one + // and assume it's a statement, then we may bail out inappropriately from whatever + // we're parsing. For example, if we have a semicolon in the middle of a class, then + // we really don't want to assume the class is over and we're on a statement in the + // outer module. We just want to consume and move on. + return !(token() === SyntaxKind.SemicolonToken && inErrorRecovery) && isStartOfStatement(); + case ParsingContext.SwitchClauses: + return token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword; + case ParsingContext.TypeMembers: + return lookAhead(isTypeMemberStart); + case ParsingContext.ClassMembers: + // We allow semicolons as class elements (as specified by ES6) as long as we're + // not in error recovery. If we're in error recovery, we don't want an errant + // semicolon to be treated as a class member (since they're almost always used + // for statements. + return lookAhead(isClassMemberStart) || (token() === SyntaxKind.SemicolonToken && !inErrorRecovery); + case ParsingContext.EnumMembers: + // Include open bracket computed properties. This technically also lets in indexers, + // which would be a candidate for improved error reporting. + return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName(); + case ParsingContext.ObjectLiteralMembers: + return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName(); + case ParsingContext.RestProperties: + return isLiteralPropertyName(); + case ParsingContext.ObjectBindingElements: + return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName(); + case ParsingContext.HeritageClauseElement: + // If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{` + // That way we won't consume the body of a class in its heritage clause. + if (token() === SyntaxKind.OpenBraceToken) { + return lookAhead(isValidHeritageClauseObjectLiteral); + } + + if (!inErrorRecovery) { + return isStartOfLeftHandSideExpression() && !isHeritageClauseExtendsOrImplementsKeyword(); + } + else { + // If we're in error recovery we tighten up what we're willing to match. + // That way we don't treat something like "this" as a valid heritage clause + // element during recovery. + return isIdentifier() && !isHeritageClauseExtendsOrImplementsKeyword(); + } + case ParsingContext.VariableDeclarations: + return isIdentifierOrPattern(); + case ParsingContext.ArrayBindingElements: + return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isIdentifierOrPattern(); + case ParsingContext.TypeParameters: + return isIdentifier(); + case ParsingContext.ArrayLiteralMembers: + if (token() === SyntaxKind.CommaToken) { + return true; + } + // falls through + case ParsingContext.ArgumentExpressions: + return token() === SyntaxKind.DotDotDotToken || isStartOfExpression(); + case ParsingContext.Parameters: + return isStartOfParameter(/*isJSDocParameter*/ false); + case ParsingContext.JSDocParameters: + return isStartOfParameter(/*isJSDocParameter*/ true); + case ParsingContext.TypeArguments: + case ParsingContext.TupleElementTypes: + return token() === SyntaxKind.CommaToken || isStartOfType(); + case ParsingContext.HeritageClauses: + return isHeritageClause(); + case ParsingContext.ImportOrExportSpecifiers: + return tokenIsIdentifierOrKeyword(token()); + case ParsingContext.JsxAttributes: + return tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.OpenBraceToken; + case ParsingContext.JsxChildren: + return true; + } + + return Debug.fail("Non-exhaustive case in 'isListElement'."); + } + + function isValidHeritageClauseObjectLiteral() { + Debug.assert(token() === SyntaxKind.OpenBraceToken); + if (nextToken() === SyntaxKind.CloseBraceToken) { + // if we see "extends {}" then only treat the {} as what we're extending (and not + // the class body) if we have: + // + // extends {} { + // extends {}, + // extends {} extends + // extends {} implements + + const next = nextToken(); + return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken || next === SyntaxKind.ExtendsKeyword || next === SyntaxKind.ImplementsKeyword; + } + + return true; + } + + function nextTokenIsIdentifier() { + nextToken(); + return isIdentifier(); + } + + function nextTokenIsIdentifierOrKeyword() { + nextToken(); + return tokenIsIdentifierOrKeyword(token()); + } + + function nextTokenIsIdentifierOrKeywordOrGreaterThan() { + nextToken(); + return tokenIsIdentifierOrKeywordOrGreaterThan(token()); + } + + function isHeritageClauseExtendsOrImplementsKeyword(): boolean { + if (token() === SyntaxKind.ImplementsKeyword || + token() === SyntaxKind.ExtendsKeyword) { + + return lookAhead(nextTokenIsStartOfExpression); + } + + return false; + } + + function nextTokenIsStartOfExpression() { + nextToken(); + return isStartOfExpression(); + } + + function nextTokenIsStartOfType() { + nextToken(); + return isStartOfType(); + } + + // True if positioned at a list terminator + function isListTerminator(kind: ParsingContext): boolean { + if (token() === SyntaxKind.EndOfFileToken) { + // Being at the end of the file ends all lists. + return true; + } + + switch (kind) { + case ParsingContext.BlockStatements: + case ParsingContext.SwitchClauses: + case ParsingContext.TypeMembers: + case ParsingContext.ClassMembers: + case ParsingContext.EnumMembers: + case ParsingContext.ObjectLiteralMembers: + case ParsingContext.ObjectBindingElements: + case ParsingContext.ImportOrExportSpecifiers: + return token() === SyntaxKind.CloseBraceToken; + case ParsingContext.SwitchClauseStatements: + return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword; + case ParsingContext.HeritageClauseElement: + return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; + case ParsingContext.VariableDeclarations: + return isVariableDeclaratorListTerminator(); + case ParsingContext.TypeParameters: + // Tokens other than '>' are here for better error recovery + return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; + case ParsingContext.ArgumentExpressions: + // Tokens other than ')' are here for better error recovery + return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.SemicolonToken; + case ParsingContext.ArrayLiteralMembers: + case ParsingContext.TupleElementTypes: + case ParsingContext.ArrayBindingElements: + return token() === SyntaxKind.CloseBracketToken; + case ParsingContext.JSDocParameters: + case ParsingContext.Parameters: + case ParsingContext.RestProperties: + // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery + return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/; + case ParsingContext.TypeArguments: + // All other tokens should cause the type-argument to terminate except comma token + return token() !== SyntaxKind.CommaToken; + case ParsingContext.HeritageClauses: + return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.CloseBraceToken; + case ParsingContext.JsxAttributes: + return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.SlashToken; + case ParsingContext.JsxChildren: + return token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsSlash); + default: + return false; + } + } + + function isVariableDeclaratorListTerminator(): boolean { + // If we can consume a semicolon (either explicitly, or with ASI), then consider us done + // with parsing the list of variable declarators. + if (canParseSemicolon()) { + return true; + } + + // in the case where we're parsing the variable declarator of a 'for-in' statement, we + // are done if we see an 'in' keyword in front of us. Same with for-of + if (isInOrOfKeyword(token())) { + return true; + } + + // ERROR RECOVERY TWEAK: + // For better error recovery, if we see an '=>' then we just stop immediately. We've got an + // arrow function here and it's going to be very unlikely that we'll resynchronize and get + // another variable declaration. + if (token() === SyntaxKind.EqualsGreaterThanToken) { + return true; + } + + // Keep trying to parse out variable declarators. + return false; + } + + // True if positioned at element or terminator of the current list or any enclosing list + function isInSomeParsingContext(): boolean { + for (let kind = 0; kind < ParsingContext.Count; kind++) { + if (parsingContext & (1 << kind)) { + if (isListElement(kind, /*inErrorRecovery*/ true) || isListTerminator(kind)) { + return true; + } + } + } + + return false; + } + + // Parses a list of elements + function parseList(kind: ParsingContext, parseElement: () => T): NodeArray { + const saveParsingContext = parsingContext; + parsingContext |= 1 << kind; + const list = []; + const listPos = getNodePos(); + + while (!isListTerminator(kind)) { + if (isListElement(kind, /*inErrorRecovery*/ false)) { + const element = parseListElement(kind, parseElement); + list.push(element); + + continue; + } + + if (abortParsingListOrMoveToNextToken(kind)) { + break; + } + } + + parsingContext = saveParsingContext; + return createNodeArray(list, listPos); + } + + function parseListElement(parsingContext: ParsingContext, parseElement: () => T): T { + const node = currentNode(parsingContext); + if (node) { + return consumeNode(node); + } + + return parseElement(); + } + + function currentNode(parsingContext: ParsingContext): Node | undefined { + // If there is an outstanding parse error that we've encountered, but not attached to + // some node, then we cannot get a node from the old source tree. This is because we + // want to mark the next node we encounter as being unusable. + // + // Note: This may be too conservative. Perhaps we could reuse the node and set the bit + // on it (or its leftmost child) as having the error. For now though, being conservative + // is nice and likely won't ever affect perf. + if (parseErrorBeforeNextFinishedNode) { + return undefined; + } + + if (!syntaxCursor) { + // if we don't have a cursor, we could never return a node from the old tree. + return undefined; + } + + const node = syntaxCursor.currentNode(scanner.getStartPos()); + + // Can't reuse a missing node. + if (nodeIsMissing(node)) { + return undefined; + } + + // Can't reuse a node that intersected the change range. + if (node.intersectsChange) { + return undefined; + } + + // Can't reuse a node that contains a parse error. This is necessary so that we + // produce the same set of errors again. + if (containsParseError(node)) { + return undefined; + } + + // We can only reuse a node if it was parsed under the same strict mode that we're + // currently in. i.e. if we originally parsed a node in non-strict mode, but then + // the user added 'using strict' at the top of the file, then we can't use that node + // again as the presence of strict mode may cause us to parse the tokens in the file + // differently. + // + // Note: we *can* reuse tokens when the strict mode changes. That's because tokens + // are unaffected by strict mode. It's just the parser will decide what to do with it + // differently depending on what mode it is in. + // + // This also applies to all our other context flags as well. + const nodeContextFlags = node.flags & NodeFlags.ContextFlags; + if (nodeContextFlags !== contextFlags) { + return undefined; + } + + // Ok, we have a node that looks like it could be reused. Now verify that it is valid + // in the current list parsing context that we're currently at. + if (!canReuseNode(node, parsingContext)) { + return undefined; + } + + if ((node as JSDocContainer).jsDocCache) { + // jsDocCache may include tags from parent nodes, which might have been modified. + (node as JSDocContainer).jsDocCache = undefined; + } + + return node; + } + + function consumeNode(node: Node) { + // Move the scanner so it is after the node we just consumed. + scanner.setTextPos(node.end); + nextToken(); + return node; + } + + function canReuseNode(node: Node, parsingContext: ParsingContext): boolean { + switch (parsingContext) { + case ParsingContext.ClassMembers: + return isReusableClassMember(node); + + case ParsingContext.SwitchClauses: + return isReusableSwitchClause(node); + + case ParsingContext.SourceElements: + case ParsingContext.BlockStatements: + case ParsingContext.SwitchClauseStatements: + return isReusableStatement(node); + + case ParsingContext.EnumMembers: + return isReusableEnumMember(node); + + case ParsingContext.TypeMembers: + return isReusableTypeMember(node); + + case ParsingContext.VariableDeclarations: + return isReusableVariableDeclaration(node); + + case ParsingContext.JSDocParameters: + case ParsingContext.Parameters: + return isReusableParameter(node); + + case ParsingContext.RestProperties: + return false; + + // Any other lists we do not care about reusing nodes in. But feel free to add if + // you can do so safely. Danger areas involve nodes that may involve speculative + // parsing. If speculative parsing is involved with the node, then the range the + // parser reached while looking ahead might be in the edited range (see the example + // in canReuseVariableDeclaratorNode for a good case of this). + case ParsingContext.HeritageClauses: + // This would probably be safe to reuse. There is no speculative parsing with + // heritage clauses. + + case ParsingContext.TypeParameters: + // This would probably be safe to reuse. There is no speculative parsing with + // type parameters. Note that that's because type *parameters* only occur in + // unambiguous *type* contexts. While type *arguments* occur in very ambiguous + // *expression* contexts. + + case ParsingContext.TupleElementTypes: + // This would probably be safe to reuse. There is no speculative parsing with + // tuple types. + + // Technically, type argument list types are probably safe to reuse. While + // speculative parsing is involved with them (since type argument lists are only + // produced from speculative parsing a < as a type argument list), we only have + // the types because speculative parsing succeeded. Thus, the lookahead never + // went past the end of the list and rewound. + case ParsingContext.TypeArguments: + + // Note: these are almost certainly not safe to ever reuse. Expressions commonly + // need a large amount of lookahead, and we should not reuse them as they may + // have actually intersected the edit. + case ParsingContext.ArgumentExpressions: + + // This is not safe to reuse for the same reason as the 'AssignmentExpression' + // cases. i.e. a property assignment may end with an expression, and thus might + // have lookahead far beyond it's old node. + case ParsingContext.ObjectLiteralMembers: + + // This is probably not safe to reuse. There can be speculative parsing with + // type names in a heritage clause. There can be generic names in the type + // name list, and there can be left hand side expressions (which can have type + // arguments.) + case ParsingContext.HeritageClauseElement: + + // Perhaps safe to reuse, but it's unlikely we'd see more than a dozen attributes + // on any given element. Same for children. + case ParsingContext.JsxAttributes: + case ParsingContext.JsxChildren: + + } + + return false; + } + + function isReusableClassMember(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.Constructor: + case SyntaxKind.IndexSignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.SemicolonClassElement: + return true; + case SyntaxKind.MethodDeclaration: + // Method declarations are not necessarily reusable. An object-literal + // may have a method calls "constructor(...)" and we must reparse that + // into an actual .ConstructorDeclaration. + const methodDeclaration = node; + const nameIsConstructor = methodDeclaration.name.kind === SyntaxKind.Identifier && + methodDeclaration.name.originalKeywordKind === SyntaxKind.ConstructorKeyword; + + return !nameIsConstructor; + } + } + + return false; + } + + function isReusableSwitchClause(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.CaseClause: + case SyntaxKind.DefaultClause: + return true; + } + } + + return false; + } + + function isReusableStatement(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.VariableStatement: + case SyntaxKind.Block: + case SyntaxKind.IfStatement: + case SyntaxKind.ExpressionStatement: + case SyntaxKind.ThrowStatement: + case SyntaxKind.ReturnStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.BreakStatement: + case SyntaxKind.ContinueStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.EmptyStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.LabeledStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.DebuggerStatement: + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ExportDeclaration: + case SyntaxKind.ExportAssignment: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.TypeAliasDeclaration: + return true; + } + } + + return false; + } + + function isReusableEnumMember(node: Node) { + return node.kind === SyntaxKind.EnumMember; + } + + function isReusableTypeMember(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.ConstructSignature: + case SyntaxKind.MethodSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.PropertySignature: + case SyntaxKind.CallSignature: + return true; + } + } + + return false; + } + + function isReusableVariableDeclaration(node: Node) { + if (node.kind !== SyntaxKind.VariableDeclaration) { + return false; + } + + // Very subtle incremental parsing bug. Consider the following code: + // + // let v = new List < A, B + // + // This is actually legal code. It's a list of variable declarators "v = new List() + // + // then we have a problem. "v = new Listnode; + return variableDeclarator.initializer === undefined; + } + + function isReusableParameter(node: Node) { + if (node.kind !== SyntaxKind.Parameter) { + return false; + } + + // See the comment in isReusableVariableDeclaration for why we do this. + const parameter = node; + return parameter.initializer === undefined; + } + + // Returns true if we should abort parsing. + function abortParsingListOrMoveToNextToken(kind: ParsingContext) { + parseErrorAtCurrentToken(parsingContextErrors(kind)); + if (isInSomeParsingContext()) { + return true; + } + + nextToken(); + return false; + } + + function parsingContextErrors(context: ParsingContext): DiagnosticMessage { + switch (context) { + case ParsingContext.SourceElements: return Diagnostics.Declaration_or_statement_expected; + case ParsingContext.BlockStatements: return Diagnostics.Declaration_or_statement_expected; + case ParsingContext.SwitchClauses: return Diagnostics.case_or_default_expected; + case ParsingContext.SwitchClauseStatements: return Diagnostics.Statement_expected; + case ParsingContext.RestProperties: // fallthrough + case ParsingContext.TypeMembers: return Diagnostics.Property_or_signature_expected; + case ParsingContext.ClassMembers: return Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected; + case ParsingContext.EnumMembers: return Diagnostics.Enum_member_expected; + case ParsingContext.HeritageClauseElement: return Diagnostics.Expression_expected; + case ParsingContext.VariableDeclarations: return Diagnostics.Variable_declaration_expected; + case ParsingContext.ObjectBindingElements: return Diagnostics.Property_destructuring_pattern_expected; + case ParsingContext.ArrayBindingElements: return Diagnostics.Array_element_destructuring_pattern_expected; + case ParsingContext.ArgumentExpressions: return Diagnostics.Argument_expression_expected; + case ParsingContext.ObjectLiteralMembers: return Diagnostics.Property_assignment_expected; + case ParsingContext.ArrayLiteralMembers: return Diagnostics.Expression_or_comma_expected; + case ParsingContext.JSDocParameters: return Diagnostics.Parameter_declaration_expected; + case ParsingContext.Parameters: return Diagnostics.Parameter_declaration_expected; + case ParsingContext.TypeParameters: return Diagnostics.Type_parameter_declaration_expected; + case ParsingContext.TypeArguments: return Diagnostics.Type_argument_expected; + case ParsingContext.TupleElementTypes: return Diagnostics.Type_expected; + case ParsingContext.HeritageClauses: return Diagnostics.Unexpected_token_expected; + case ParsingContext.ImportOrExportSpecifiers: return Diagnostics.Identifier_expected; + case ParsingContext.JsxAttributes: return Diagnostics.Identifier_expected; + case ParsingContext.JsxChildren: return Diagnostics.Identifier_expected; + default: return undefined!; // TODO: GH#18217 `default: Debug.assertNever(context);` + } + } + + // Parses a comma-delimited list of elements + function parseDelimitedList(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray { + const saveParsingContext = parsingContext; + parsingContext |= 1 << kind; + const list = []; + const listPos = getNodePos(); + + let commaStart = -1; // Meaning the previous token was not a comma + while (true) { + if (isListElement(kind, /*inErrorRecovery*/ false)) { + const startPos = scanner.getStartPos(); + list.push(parseListElement(kind, parseElement)); + commaStart = scanner.getTokenPos(); + + if (parseOptional(SyntaxKind.CommaToken)) { + // No need to check for a zero length node since we know we parsed a comma + continue; + } + + commaStart = -1; // Back to the state where the last token was not a comma + if (isListTerminator(kind)) { + break; + } + + // We didn't get a comma, and the list wasn't terminated, explicitly parse + // out a comma so we give a good error message. + parseExpected(SyntaxKind.CommaToken); + + // If the token was a semicolon, and the caller allows that, then skip it and + // continue. This ensures we get back on track and don't result in tons of + // parse errors. For example, this can happen when people do things like use + // a semicolon to delimit object literal members. Note: we'll have already + // reported an error when we called parseExpected above. + if (considerSemicolonAsDelimiter && token() === SyntaxKind.SemicolonToken && !scanner.hasPrecedingLineBreak()) { + nextToken(); + } + if (startPos === scanner.getStartPos()) { + // What we're parsing isn't actually remotely recognizable as a element and we've consumed no tokens whatsoever + // Consume a token to advance the parser in some way and avoid an infinite loop + // This can happen when we're speculatively parsing parenthesized expressions which we think may be arrow functions, + // or when a modifier keyword which is disallowed as a parameter name (ie, `static` in strict mode) is supplied + nextToken(); + } + continue; + } + + if (isListTerminator(kind)) { + break; + } + + if (abortParsingListOrMoveToNextToken(kind)) { + break; + } + } + + parsingContext = saveParsingContext; + const result = createNodeArray(list, listPos); + // Recording the trailing comma is deliberately done after the previous + // loop, and not just if we see a list terminator. This is because the list + // may have ended incorrectly, but it is still important to know if there + // was a trailing comma. + // Check if the last token was a comma. + if (commaStart >= 0) { + // Always preserve a trailing comma by marking it on the NodeArray + result.hasTrailingComma = true; + } + return result; + } + + interface MissingList extends NodeArray { + isMissingList: true; + } + + function createMissingList(): MissingList { + const list = createNodeArray([], getNodePos()) as MissingList; + list.isMissingList = true; + return list; + } + + function isMissingList(arr: NodeArray): boolean { + return !!(arr as MissingList).isMissingList; + } + + function parseBracketedList(kind: ParsingContext, parseElement: () => T, open: SyntaxKind, close: SyntaxKind): NodeArray { + if (parseExpected(open)) { + const result = parseDelimitedList(kind, parseElement); + parseExpected(close); + return result; + } + + return createMissingList(); + } + + function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName { + let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage); + let dotPos = scanner.getStartPos(); + while (parseOptional(SyntaxKind.DotToken)) { + if (token() === SyntaxKind.LessThanToken) { + // the entity is part of a JSDoc-style generic, so record the trailing dot for later error reporting + entity.jsdocDotPos = dotPos; + break; + } + dotPos = scanner.getStartPos(); + entity = createQualifiedName(entity, parseRightSideOfDot(allowReservedWords)); + } + return entity; + } + + function createQualifiedName(entity: EntityName, name: Identifier): QualifiedName { + const node = createNode(SyntaxKind.QualifiedName, entity.pos) as QualifiedName; + node.left = entity; + node.right = name; + return finishNode(node); + } + + function parseRightSideOfDot(allowIdentifierNames: boolean): Identifier { + // Technically a keyword is valid here as all identifiers and keywords are identifier names. + // However, often we'll encounter this in error situations when the identifier or keyword + // is actually starting another valid construct. + // + // So, we check for the following specific case: + // + // name. + // identifierOrKeyword identifierNameOrKeyword + // + // Note: the newlines are important here. For example, if that above code + // were rewritten into: + // + // name.identifierOrKeyword + // identifierNameOrKeyword + // + // Then we would consider it valid. That's because ASI would take effect and + // the code would be implicitly: "name.identifierOrKeyword; identifierNameOrKeyword". + // In the first case though, ASI will not take effect because there is not a + // line terminator after the identifier or keyword. + if (scanner.hasPrecedingLineBreak() && tokenIsIdentifierOrKeyword(token())) { + const matchesPattern = lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine); + + if (matchesPattern) { + // Report that we need an identifier. However, report it right after the dot, + // and not on the next token. This is because the next token might actually + // be an identifier and the error would be quite confusing. + return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); + } + } + + return allowIdentifierNames ? parseIdentifierName() : parseIdentifier(); + } + + function parseTemplateExpression(): TemplateExpression { + const template = createNode(SyntaxKind.TemplateExpression); + + template.head = parseTemplateHead(); + Debug.assert(template.head.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind"); + + const list = []; + const listPos = getNodePos(); + + do { + list.push(parseTemplateSpan()); + } + while (last(list).literal.kind === SyntaxKind.TemplateMiddle); + + template.templateSpans = createNodeArray(list, listPos); + + return finishNode(template); + } + + function parseTemplateSpan(): TemplateSpan { + const span = createNode(SyntaxKind.TemplateSpan); + span.expression = allowInAnd(parseExpression); + + let literal: TemplateMiddle | TemplateTail; + if (token() === SyntaxKind.CloseBraceToken) { + reScanTemplateToken(); + literal = parseTemplateMiddleOrTemplateTail(); + } + else { + literal = parseExpectedToken(SyntaxKind.TemplateTail, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken)); + } + + span.literal = literal; + return finishNode(span); + } + + function parseLiteralNode(): LiteralExpression { + return parseLiteralLikeNode(token()); + } + + function parseTemplateHead(): TemplateHead { + const fragment = parseLiteralLikeNode(token()); + Debug.assert(fragment.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind"); + return fragment; + } + + function parseTemplateMiddleOrTemplateTail(): TemplateMiddle | TemplateTail { + const fragment = parseLiteralLikeNode(token()); + Debug.assert(fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, "Template fragment has wrong token kind"); + return fragment; + } + + function parseLiteralLikeNode(kind: SyntaxKind): LiteralExpression | LiteralLikeNode { + const node = createNode(kind); + const text = scanner.getTokenValue(); + node.text = text; + + if (scanner.hasExtendedUnicodeEscape()) { + node.hasExtendedUnicodeEscape = true; + } + + if (scanner.isUnterminated()) { + node.isUnterminated = true; + } + + // Octal literals are not allowed in strict mode or ES5 + // Note that theoretically the following condition would hold true literals like 009, + // which is not octal.But because of how the scanner separates the tokens, we would + // never get a token like this. Instead, we would get 00 and 9 as two separate tokens. + // We also do not need to check for negatives because any prefix operator would be part of a + // parent unary expression. + if (node.kind === SyntaxKind.NumericLiteral) { + (node).numericLiteralFlags = scanner.getTokenFlags() & TokenFlags.NumericLiteralFlags; + } + + nextToken(); + finishNode(node); + + return node; + } + + // TYPES + + function parseTypeReference(): TypeReferenceNode { + const node = createNode(SyntaxKind.TypeReference); + node.typeName = parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected); + if (!scanner.hasPrecedingLineBreak() && token() === SyntaxKind.LessThanToken) { + node.typeArguments = parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); + } + return finishNode(node); + } + + // If true, we should abort parsing an error function. + function typeHasArrowFunctionBlockingParseError(node: TypeNode): boolean { + switch (node.kind) { + case SyntaxKind.TypeReference: + return nodeIsMissing((node as TypeReferenceNode).typeName); + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: { + const { parameters, type } = node as FunctionOrConstructorTypeNode; + return isMissingList(parameters) || typeHasArrowFunctionBlockingParseError(type); + } + case SyntaxKind.ParenthesizedType: + return typeHasArrowFunctionBlockingParseError((node as ParenthesizedTypeNode).type); + default: + return false; + } + } + + function parseThisTypePredicate(lhs: ThisTypeNode): TypePredicateNode { + nextToken(); + const node = createNode(SyntaxKind.TypePredicate, lhs.pos) as TypePredicateNode; + node.parameterName = lhs; + node.type = parseType(); + return finishNode(node); + } + + function parseThisTypeNode(): ThisTypeNode { + const node = createNode(SyntaxKind.ThisType) as ThisTypeNode; + nextToken(); + return finishNode(node); + } + + function parseJSDocAllType(postFixEquals: boolean): JSDocAllType | JSDocOptionalType { + const result = createNode(SyntaxKind.JSDocAllType) as JSDocAllType; + if (postFixEquals) { + return createPostfixType(SyntaxKind.JSDocOptionalType, result) as JSDocOptionalType; + } + else { + nextToken(); + } + return finishNode(result); + } + + function parseJSDocNonNullableType(): TypeNode { + const result = createNode(SyntaxKind.JSDocNonNullableType) as JSDocNonNullableType; + nextToken(); + result.type = parseNonArrayType(); + return finishNode(result); + } + + function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType { + const pos = scanner.getStartPos(); + // skip the ? + nextToken(); + + // Need to lookahead to decide if this is a nullable or unknown type. + + // Here are cases where we'll pick the unknown type: + // + // Foo(?, + // { a: ? } + // Foo(?) + // Foo + // Foo(?= + // (?| + if (token() === SyntaxKind.CommaToken || + token() === SyntaxKind.CloseBraceToken || + token() === SyntaxKind.CloseParenToken || + token() === SyntaxKind.GreaterThanToken || + token() === SyntaxKind.EqualsToken || + token() === SyntaxKind.BarToken) { + + const result = createNode(SyntaxKind.JSDocUnknownType, pos); + return finishNode(result); + } + else { + const result = createNode(SyntaxKind.JSDocNullableType, pos); + result.type = parseType(); + return finishNode(result); + } + } + + function parseJSDocFunctionType(): JSDocFunctionType | TypeReferenceNode { + if (lookAhead(nextTokenIsOpenParen)) { + const result = createNodeWithJSDoc(SyntaxKind.JSDocFunctionType); + nextToken(); + fillSignature(SyntaxKind.ColonToken, SignatureFlags.Type | SignatureFlags.JSDoc, result); + return finishNode(result); + } + const node = createNode(SyntaxKind.TypeReference); + node.typeName = parseIdentifierName(); + return finishNode(node); + } + + function parseJSDocParameter(): ParameterDeclaration { + const parameter = createNode(SyntaxKind.Parameter) as ParameterDeclaration; + if (token() === SyntaxKind.ThisKeyword || token() === SyntaxKind.NewKeyword) { + parameter.name = parseIdentifierName(); + parseExpected(SyntaxKind.ColonToken); + } + parameter.type = parseJSDocType(); + return finishNode(parameter); + } + + function parseJSDocType(): TypeNode { + const dotdotdot = parseOptionalToken(SyntaxKind.DotDotDotToken); + let type = parseTypeOrTypePredicate(); + if (dotdotdot) { + const variadic = createNode(SyntaxKind.JSDocVariadicType, dotdotdot.pos) as JSDocVariadicType; + variadic.type = type; + type = finishNode(variadic); + } + if (token() === SyntaxKind.EqualsToken) { + return createPostfixType(SyntaxKind.JSDocOptionalType, type); + } + return type; + } + + function parseTypeQuery(): TypeQueryNode { + const node = createNode(SyntaxKind.TypeQuery); + parseExpected(SyntaxKind.TypeOfKeyword); + node.exprName = parseEntityName(/*allowReservedWords*/ true); + return finishNode(node); + } + + function parseTypeParameter(): TypeParameterDeclaration { + const node = createNode(SyntaxKind.TypeParameter); + node.name = parseIdentifier(); + if (parseOptional(SyntaxKind.ExtendsKeyword)) { + // It's not uncommon for people to write improper constraints to a generic. If the + // user writes a constraint that is an expression and not an actual type, then parse + // it out as an expression (so we can recover well), but report that a type is needed + // instead. + if (isStartOfType() || !isStartOfExpression()) { + node.constraint = parseType(); + } + else { + // It was not a type, and it looked like an expression. Parse out an expression + // here so we recover well. Note: it is important that we call parseUnaryExpression + // and not parseExpression here. If the user has: + // + // + // + // We do *not* want to consume the `>` as we're consuming the expression for "". + node.expression = parseUnaryExpressionOrHigher(); + } + } + + if (parseOptional(SyntaxKind.EqualsToken)) { + node.default = parseType(); + } + + return finishNode(node); + } + + function parseTypeParameters(): NodeArray | undefined { + if (token() === SyntaxKind.LessThanToken) { + return parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); + } + } + + function parseParameterType(): TypeNode | undefined { + if (parseOptional(SyntaxKind.ColonToken)) { + return parseType(); + } + + return undefined; + } + + function isStartOfParameter(isJSDocParameter: boolean): boolean { + return token() === SyntaxKind.DotDotDotToken || + isIdentifierOrPattern() || + isModifierKind(token()) || + token() === SyntaxKind.AtToken || + isStartOfType(/*inStartOfParameter*/ !isJSDocParameter); + } + + function parseParameter(): ParameterDeclaration { + const node = createNodeWithJSDoc(SyntaxKind.Parameter); + if (token() === SyntaxKind.ThisKeyword) { + node.name = createIdentifier(/*isIdentifier*/ true); + node.type = parseParameterType(); + return finishNode(node); + } + + node.decorators = parseDecorators(); + node.modifiers = parseModifiers(); + node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); + + // FormalParameter [Yield,Await]: + // BindingElement[?Yield,?Await] + node.name = parseIdentifierOrPattern(); + if (getFullWidth(node.name) === 0 && !hasModifiers(node) && isModifierKind(token())) { + // in cases like + // 'use strict' + // function foo(static) + // isParameter('static') === true, because of isModifier('static') + // however 'static' is not a legal identifier in a strict mode. + // so result of this function will be ParameterDeclaration (flags = 0, name = missing, type = undefined, initializer = undefined) + // and current token will not change => parsing of the enclosing parameter list will last till the end of time (or OOM) + // to avoid this we'll advance cursor to the next token. + nextToken(); + } + + node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken); + node.type = parseParameterType(); + node.initializer = parseInitializer(); + + return finishNode(node); + } + + /** + * Note: If returnToken is EqualsGreaterThanToken, `signature.type` will always be defined. + * @returns - If return type parsing succeeds + */ + function fillSignature( + returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, + flags: SignatureFlags, + signature: SignatureDeclaration): boolean { + if (!(flags & SignatureFlags.JSDoc)) { + signature.typeParameters = parseTypeParameters(); + } + const parametersParsedSuccessfully = parseParameterList(signature, flags); + if (shouldParseReturnType(returnToken, !!(flags & SignatureFlags.Type))) { + signature.type = parseTypeOrTypePredicate(); + if (typeHasArrowFunctionBlockingParseError(signature.type)) return false; + } + return parametersParsedSuccessfully; + } + + function shouldParseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): boolean { + if (returnToken === SyntaxKind.EqualsGreaterThanToken) { + parseExpected(returnToken); + return true; + } + else if (parseOptional(SyntaxKind.ColonToken)) { + return true; + } + else if (isType && token() === SyntaxKind.EqualsGreaterThanToken) { + // This is easy to get backward, especially in type contexts, so parse the type anyway + parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken)); + nextToken(); + return true; + } + return false; + } + + // Returns true on success. + function parseParameterList(signature: SignatureDeclaration, flags: SignatureFlags): boolean { + // FormalParameters [Yield,Await]: (modified) + // [empty] + // FormalParameterList[?Yield,Await] + // + // FormalParameter[Yield,Await]: (modified) + // BindingElement[?Yield,Await] + // + // BindingElement [Yield,Await]: (modified) + // SingleNameBinding[?Yield,?Await] + // BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt + // + // SingleNameBinding [Yield,Await]: + // BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt + if (!parseExpected(SyntaxKind.OpenParenToken)) { + signature.parameters = createMissingList(); + return false; + } + + const savedYieldContext = inYieldContext(); + const savedAwaitContext = inAwaitContext(); + + setYieldContext(!!(flags & SignatureFlags.Yield)); + setAwaitContext(!!(flags & SignatureFlags.Await)); + + signature.parameters = flags & SignatureFlags.JSDoc ? + parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) : + parseDelimitedList(ParsingContext.Parameters, parseParameter); + + setYieldContext(savedYieldContext); + setAwaitContext(savedAwaitContext); + + return parseExpected(SyntaxKind.CloseParenToken); + } + + function parseTypeMemberSemicolon() { + // We allow type members to be separated by commas or (possibly ASI) semicolons. + // First check if it was a comma. If so, we're done with the member. + if (parseOptional(SyntaxKind.CommaToken)) { + return; + } + + // Didn't have a comma. We must have a (possible ASI) semicolon. + parseSemicolon(); + } + + function parseSignatureMember(kind: SyntaxKind.CallSignature | SyntaxKind.ConstructSignature): CallSignatureDeclaration | ConstructSignatureDeclaration { + const node = createNodeWithJSDoc(kind); + if (kind === SyntaxKind.ConstructSignature) { + parseExpected(SyntaxKind.NewKeyword); + } + fillSignature(SyntaxKind.ColonToken, SignatureFlags.Type, node); + parseTypeMemberSemicolon(); + return finishNode(node); + } + + function isIndexSignature(): boolean { + return token() === SyntaxKind.OpenBracketToken && lookAhead(isUnambiguouslyIndexSignature); + } + + function isUnambiguouslyIndexSignature() { + // The only allowed sequence is: + // + // [id: + // + // However, for error recovery, we also check the following cases: + // + // [... + // [id, + // [id?, + // [id?: + // [id?] + // [public id + // [private id + // [protected id + // [] + // + nextToken(); + if (token() === SyntaxKind.DotDotDotToken || token() === SyntaxKind.CloseBracketToken) { + return true; + } + + if (isModifierKind(token())) { + nextToken(); + if (isIdentifier()) { + return true; + } + } + else if (!isIdentifier()) { + return false; + } + else { + // Skip the identifier + nextToken(); + } + + // A colon signifies a well formed indexer + // A comma should be a badly formed indexer because comma expressions are not allowed + // in computed properties. + if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken) { + return true; + } + + // Question mark could be an indexer with an optional property, + // or it could be a conditional expression in a computed property. + if (token() !== SyntaxKind.QuestionToken) { + return false; + } + + // If any of the following tokens are after the question mark, it cannot + // be a conditional expression, so treat it as an indexer. + nextToken(); + return token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.CloseBracketToken; + } + + function parseIndexSignatureDeclaration(node: IndexSignatureDeclaration): IndexSignatureDeclaration { + node.kind = SyntaxKind.IndexSignature; + node.parameters = parseBracketedList(ParsingContext.Parameters, parseParameter, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); + node.type = parseTypeAnnotation(); + parseTypeMemberSemicolon(); + return finishNode(node); + } + + function parsePropertyOrMethodSignature(node: PropertySignature | MethodSignature): PropertySignature | MethodSignature { + node.name = parsePropertyName(); + node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken); + if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { + node.kind = SyntaxKind.MethodSignature; + // Method signatures don't exist in expression contexts. So they have neither + // [Yield] nor [Await] + fillSignature(SyntaxKind.ColonToken, SignatureFlags.Type, node); + } + else { + node.kind = SyntaxKind.PropertySignature; + node.type = parseTypeAnnotation(); + if (token() === SyntaxKind.EqualsToken) { + // Although type literal properties cannot not have initializers, we attempt + // to parse an initializer so we can report in the checker that an interface + // property or type literal property cannot have an initializer. + (node).initializer = parseInitializer(); + } + } + parseTypeMemberSemicolon(); + return finishNode(node); + } + + function isTypeMemberStart(): boolean { + // Return true if we have the start of a signature member + if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { + return true; + } + let idToken = false; + // Eat up all modifiers, but hold on to the last one in case it is actually an identifier + while (isModifierKind(token())) { + idToken = true; + nextToken(); + } + // Index signatures and computed property names are type members + if (token() === SyntaxKind.OpenBracketToken) { + return true; + } + // Try to get the first property-like token following all modifiers + if (isLiteralPropertyName()) { + idToken = true; + nextToken(); + } + // If we were able to get any potential identifier, check that it is + // the start of a member declaration + if (idToken) { + return token() === SyntaxKind.OpenParenToken || + token() === SyntaxKind.LessThanToken || + token() === SyntaxKind.QuestionToken || + token() === SyntaxKind.ColonToken || + token() === SyntaxKind.CommaToken || + canParseSemicolon(); + } + return false; + } + + function parseTypeMember(): TypeElement { + if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { + return parseSignatureMember(SyntaxKind.CallSignature); + } + if (token() === SyntaxKind.NewKeyword && lookAhead(nextTokenIsOpenParenOrLessThan)) { + return parseSignatureMember(SyntaxKind.ConstructSignature); + } + const node = createNodeWithJSDoc(SyntaxKind.Unknown); + node.modifiers = parseModifiers(); + if (isIndexSignature()) { + return parseIndexSignatureDeclaration(node); + } + return parsePropertyOrMethodSignature(node); + } + + function nextTokenIsOpenParenOrLessThan() { + nextToken(); + return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken; + } + + function nextTokenIsDot() { + return nextToken() === SyntaxKind.DotToken; + } + + function nextTokenIsOpenParenOrLessThanOrDot() { + switch (nextToken()) { + case SyntaxKind.OpenParenToken: + case SyntaxKind.LessThanToken: + case SyntaxKind.DotToken: + return true; + } + return false; + } + + function parseTypeLiteral(): TypeLiteralNode { + const node = createNode(SyntaxKind.TypeLiteral); + node.members = parseObjectTypeMembers(); + return finishNode(node); + } + + function parseObjectTypeMembers(): NodeArray { + let members: NodeArray; + if (parseExpected(SyntaxKind.OpenBraceToken)) { + members = parseList(ParsingContext.TypeMembers, parseTypeMember); + parseExpected(SyntaxKind.CloseBraceToken); + } + else { + members = createMissingList(); + } + + return members; + } + + function isStartOfMappedType() { + nextToken(); + if (token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { + return nextToken() === SyntaxKind.ReadonlyKeyword; + } + if (token() === SyntaxKind.ReadonlyKeyword) { + nextToken(); + } + return token() === SyntaxKind.OpenBracketToken && nextTokenIsIdentifier() && nextToken() === SyntaxKind.InKeyword; + } + + function parseMappedTypeParameter() { + const node = createNode(SyntaxKind.TypeParameter); + node.name = parseIdentifier(); + parseExpected(SyntaxKind.InKeyword); + node.constraint = parseType(); + return finishNode(node); + } + + function parseMappedType() { + const node = createNode(SyntaxKind.MappedType); + parseExpected(SyntaxKind.OpenBraceToken); + if (token() === SyntaxKind.ReadonlyKeyword || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { + node.readonlyToken = parseTokenNode(); + if (node.readonlyToken.kind !== SyntaxKind.ReadonlyKeyword) { + parseExpectedToken(SyntaxKind.ReadonlyKeyword); + } + } + parseExpected(SyntaxKind.OpenBracketToken); + node.typeParameter = parseMappedTypeParameter(); + parseExpected(SyntaxKind.CloseBracketToken); + if (token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { + node.questionToken = parseTokenNode(); + if (node.questionToken.kind !== SyntaxKind.QuestionToken) { + parseExpectedToken(SyntaxKind.QuestionToken); + } + } + node.type = parseTypeAnnotation(); + parseSemicolon(); + parseExpected(SyntaxKind.CloseBraceToken); + return finishNode(node); + } + + function parseTupleElementType() { + const pos = getNodePos(); + if (parseOptional(SyntaxKind.DotDotDotToken)) { + const node = createNode(SyntaxKind.RestType, pos); + node.type = parseType(); + return finishNode(node); + } + const type = parseType(); + if (!(contextFlags & NodeFlags.JSDoc) && type.kind === SyntaxKind.JSDocNullableType && type.pos === (type).type.pos) { + type.kind = SyntaxKind.OptionalType; + } + return type; + } + + function parseTupleType(): TupleTypeNode { + const node = createNode(SyntaxKind.TupleType); + node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); + return finishNode(node); + } + + function parseParenthesizedType(): TypeNode { + const node = createNode(SyntaxKind.ParenthesizedType); + parseExpected(SyntaxKind.OpenParenToken); + node.type = parseType(); + parseExpected(SyntaxKind.CloseParenToken); + return finishNode(node); + } + + function parseFunctionOrConstructorType(): TypeNode { + const pos = getNodePos(); + const kind = parseOptional(SyntaxKind.NewKeyword) ? SyntaxKind.ConstructorType : SyntaxKind.FunctionType; + const node = createNodeWithJSDoc(kind, pos); + fillSignature(SyntaxKind.EqualsGreaterThanToken, SignatureFlags.Type, node); + return finishNode(node); + } + + function parseKeywordAndNoDot(): TypeNode | undefined { + const node = parseTokenNode(); + return token() === SyntaxKind.DotToken ? undefined : node; + } + + function parseLiteralTypeNode(negative?: boolean): LiteralTypeNode { + const node = createNode(SyntaxKind.LiteralType) as LiteralTypeNode; + let unaryMinusExpression!: PrefixUnaryExpression; + if (negative) { + unaryMinusExpression = createNode(SyntaxKind.PrefixUnaryExpression) as PrefixUnaryExpression; + unaryMinusExpression.operator = SyntaxKind.MinusToken; + nextToken(); + } + let expression: BooleanLiteral | LiteralExpression | PrefixUnaryExpression = token() === SyntaxKind.TrueKeyword || token() === SyntaxKind.FalseKeyword + ? parseTokenNode() + : parseLiteralLikeNode(token()) as LiteralExpression; + if (negative) { + unaryMinusExpression.operand = expression; + finishNode(unaryMinusExpression); + expression = unaryMinusExpression; + } + node.literal = expression; + return finishNode(node); + } + + function isStartOfTypeOfImportType() { + nextToken(); + return token() === SyntaxKind.ImportKeyword; + } + + function parseImportType(): ImportTypeNode { + sourceFile.flags |= NodeFlags.PossiblyContainsDynamicImport; + const node = createNode(SyntaxKind.ImportType) as ImportTypeNode; + if (parseOptional(SyntaxKind.TypeOfKeyword)) { + node.isTypeOf = true; + } + parseExpected(SyntaxKind.ImportKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.argument = parseType(); + parseExpected(SyntaxKind.CloseParenToken); + if (parseOptional(SyntaxKind.DotToken)) { + node.qualifier = parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected); + } + node.typeArguments = tryParseTypeArguments(); + return finishNode(node); + } + + function nextTokenIsNumericLiteral() { + return nextToken() === SyntaxKind.NumericLiteral; + } + + function parseNonArrayType(): TypeNode { + switch (token()) { + case SyntaxKind.AnyKeyword: + case SyntaxKind.UnknownKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.SymbolKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.UndefinedKeyword: + case SyntaxKind.NeverKeyword: + case SyntaxKind.ObjectKeyword: + // If these are followed by a dot, then parse these out as a dotted type reference instead. + return tryParse(parseKeywordAndNoDot) || parseTypeReference(); + case SyntaxKind.AsteriskToken: + return parseJSDocAllType(/*postfixEquals*/ false); + case SyntaxKind.AsteriskEqualsToken: + return parseJSDocAllType(/*postfixEquals*/ true); + case SyntaxKind.QuestionToken: + return parseJSDocUnknownOrNullableType(); + case SyntaxKind.FunctionKeyword: + return parseJSDocFunctionType(); + case SyntaxKind.ExclamationToken: + return parseJSDocNonNullableType(); + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.StringLiteral: + case SyntaxKind.NumericLiteral: + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + return parseLiteralTypeNode(); + case SyntaxKind.MinusToken: + return lookAhead(nextTokenIsNumericLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference(); + case SyntaxKind.VoidKeyword: + case SyntaxKind.NullKeyword: + return parseTokenNode(); + case SyntaxKind.ThisKeyword: { + const thisKeyword = parseThisTypeNode(); + if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { + return parseThisTypePredicate(thisKeyword); + } + else { + return thisKeyword; + } + } + case SyntaxKind.TypeOfKeyword: + return lookAhead(isStartOfTypeOfImportType) ? parseImportType() : parseTypeQuery(); + case SyntaxKind.OpenBraceToken: + return lookAhead(isStartOfMappedType) ? parseMappedType() : parseTypeLiteral(); + case SyntaxKind.OpenBracketToken: + return parseTupleType(); + case SyntaxKind.OpenParenToken: + return parseParenthesizedType(); + case SyntaxKind.ImportKeyword: + return parseImportType(); + default: + return parseTypeReference(); + } + } + + function isStartOfType(inStartOfParameter?: boolean): boolean { + switch (token()) { + case SyntaxKind.AnyKeyword: + case SyntaxKind.UnknownKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.SymbolKeyword: + case SyntaxKind.UniqueKeyword: + case SyntaxKind.VoidKeyword: + case SyntaxKind.UndefinedKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.ThisKeyword: + case SyntaxKind.TypeOfKeyword: + case SyntaxKind.NeverKeyword: + case SyntaxKind.OpenBraceToken: + case SyntaxKind.OpenBracketToken: + case SyntaxKind.LessThanToken: + case SyntaxKind.BarToken: + case SyntaxKind.AmpersandToken: + case SyntaxKind.NewKeyword: + case SyntaxKind.StringLiteral: + case SyntaxKind.NumericLiteral: + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + case SyntaxKind.ObjectKeyword: + case SyntaxKind.AsteriskToken: + case SyntaxKind.QuestionToken: + case SyntaxKind.ExclamationToken: + case SyntaxKind.DotDotDotToken: + case SyntaxKind.InferKeyword: + case SyntaxKind.ImportKeyword: + return true; + case SyntaxKind.FunctionKeyword: + return !inStartOfParameter; + case SyntaxKind.MinusToken: + return !inStartOfParameter && lookAhead(nextTokenIsNumericLiteral); + case SyntaxKind.OpenParenToken: + // Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier, + // or something that starts a type. We don't want to consider things like '(1)' a type. + return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType); + default: + return isIdentifier(); + } + } + + function isStartOfParenthesizedOrFunctionType() { + nextToken(); + return token() === SyntaxKind.CloseParenToken || isStartOfParameter(/*isJSDocParameter*/ false) || isStartOfType(); + } + + function parsePostfixTypeOrHigher(): TypeNode { + let type = parseNonArrayType(); + while (!scanner.hasPrecedingLineBreak()) { + switch (token()) { + case SyntaxKind.ExclamationToken: + type = createPostfixType(SyntaxKind.JSDocNonNullableType, type); + break; + case SyntaxKind.QuestionToken: + // If not in JSDoc and next token is start of a type we have a conditional type + if (!(contextFlags & NodeFlags.JSDoc) && lookAhead(nextTokenIsStartOfType)) { + return type; + } + type = createPostfixType(SyntaxKind.JSDocNullableType, type); + break; + case SyntaxKind.OpenBracketToken: + parseExpected(SyntaxKind.OpenBracketToken); + if (isStartOfType()) { + const node = createNode(SyntaxKind.IndexedAccessType, type.pos) as IndexedAccessTypeNode; + node.objectType = type; + node.indexType = parseType(); + parseExpected(SyntaxKind.CloseBracketToken); + type = finishNode(node); + } + else { + const node = createNode(SyntaxKind.ArrayType, type.pos) as ArrayTypeNode; + node.elementType = type; + parseExpected(SyntaxKind.CloseBracketToken); + type = finishNode(node); + } + break; + default: + return type; + } + } + return type; + } + + function createPostfixType(kind: SyntaxKind, type: TypeNode) { + nextToken(); + const postfix = createNode(kind, type.pos) as OptionalTypeNode | JSDocOptionalType | JSDocNonNullableType | JSDocNullableType; + postfix.type = type; + return finishNode(postfix); + } + + function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword) { + const node = createNode(SyntaxKind.TypeOperator); + parseExpected(operator); + node.operator = operator; + node.type = parseTypeOperatorOrHigher(); + return finishNode(node); + } + + function parseInferType(): InferTypeNode { + const node = createNode(SyntaxKind.InferType); + parseExpected(SyntaxKind.InferKeyword); + const typeParameter = createNode(SyntaxKind.TypeParameter); + typeParameter.name = parseIdentifier(); + node.typeParameter = finishNode(typeParameter); + return finishNode(node); + } + + function parseTypeOperatorOrHigher(): TypeNode { + const operator = token(); + switch (operator) { + case SyntaxKind.KeyOfKeyword: + case SyntaxKind.UniqueKeyword: + return parseTypeOperator(operator); + case SyntaxKind.InferKeyword: + return parseInferType(); + } + return parsePostfixTypeOrHigher(); + } + + function parseUnionOrIntersectionType(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, parseConstituentType: () => TypeNode, operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken): TypeNode { + parseOptional(operator); + let type = parseConstituentType(); + if (token() === operator) { + const types = [type]; + while (parseOptional(operator)) { + types.push(parseConstituentType()); + } + const node = createNode(kind, type.pos); + node.types = createNodeArray(types, type.pos); + type = finishNode(node); + } + return type; + } + + function parseIntersectionTypeOrHigher(): TypeNode { + return parseUnionOrIntersectionType(SyntaxKind.IntersectionType, parseTypeOperatorOrHigher, SyntaxKind.AmpersandToken); + } + + function parseUnionTypeOrHigher(): TypeNode { + return parseUnionOrIntersectionType(SyntaxKind.UnionType, parseIntersectionTypeOrHigher, SyntaxKind.BarToken); + } + + function isStartOfFunctionType(): boolean { + if (token() === SyntaxKind.LessThanToken) { + return true; + } + return token() === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType); + } + + function skipParameterStart(): boolean { + if (isModifierKind(token())) { + // Skip modifiers + parseModifiers(); + } + if (isIdentifier() || token() === SyntaxKind.ThisKeyword) { + nextToken(); + return true; + } + if (token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken) { + // Return true if we can parse an array or object binding pattern with no errors + const previousErrorCount = parseDiagnostics.length; + parseIdentifierOrPattern(); + return previousErrorCount === parseDiagnostics.length; + } + return false; + } + + function isUnambiguouslyStartOfFunctionType() { + nextToken(); + if (token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.DotDotDotToken) { + // ( ) + // ( ... + return true; + } + if (skipParameterStart()) { + // We successfully skipped modifiers (if any) and an identifier or binding pattern, + // now see if we have something that indicates a parameter declaration + if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || + token() === SyntaxKind.QuestionToken || token() === SyntaxKind.EqualsToken) { + // ( xxx : + // ( xxx , + // ( xxx ? + // ( xxx = + return true; + } + if (token() === SyntaxKind.CloseParenToken) { + nextToken(); + if (token() === SyntaxKind.EqualsGreaterThanToken) { + // ( xxx ) => + return true; + } + } + } + return false; + } + + function parseTypeOrTypePredicate(): TypeNode { + const typePredicateVariable = isIdentifier() && tryParse(parseTypePredicatePrefix); + const type = parseType(); + if (typePredicateVariable) { + const node = createNode(SyntaxKind.TypePredicate, typePredicateVariable.pos); + node.parameterName = typePredicateVariable; + node.type = type; + return finishNode(node); + } + else { + return type; + } + } + + function parseTypePredicatePrefix() { + const id = parseIdentifier(); + if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { + nextToken(); + return id; + } + } + + function parseType(): TypeNode { + // The rules about 'yield' only apply to actual code/expression contexts. They don't + // apply to 'type' contexts. So we disable these parameters here before moving on. + return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseTypeWorker); + } + + function parseTypeWorker(noConditionalTypes?: boolean): TypeNode { + if (isStartOfFunctionType() || token() === SyntaxKind.NewKeyword) { + return parseFunctionOrConstructorType(); + } + const type = parseUnionTypeOrHigher(); + if (!noConditionalTypes && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) { + const node = createNode(SyntaxKind.ConditionalType, type.pos); + node.checkType = type; + // The type following 'extends' is not permitted to be another conditional type + node.extendsType = parseTypeWorker(/*noConditionalTypes*/ true); + parseExpected(SyntaxKind.QuestionToken); + node.trueType = parseTypeWorker(); + parseExpected(SyntaxKind.ColonToken); + node.falseType = parseTypeWorker(); + return finishNode(node); + } + return type; + } + + function parseTypeAnnotation(): TypeNode | undefined { + return parseOptional(SyntaxKind.ColonToken) ? parseType() : undefined; + } + + // EXPRESSIONS + function isStartOfLeftHandSideExpression(): boolean { + switch (token()) { + case SyntaxKind.ThisKeyword: + case SyntaxKind.SuperKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.TemplateHead: + case SyntaxKind.OpenParenToken: + case SyntaxKind.OpenBracketToken: + case SyntaxKind.OpenBraceToken: + case SyntaxKind.FunctionKeyword: + case SyntaxKind.ClassKeyword: + case SyntaxKind.NewKeyword: + case SyntaxKind.SlashToken: + case SyntaxKind.SlashEqualsToken: + case SyntaxKind.Identifier: + return true; + case SyntaxKind.ImportKeyword: + return lookAhead(nextTokenIsOpenParenOrLessThanOrDot); + default: + return isIdentifier(); + } + } + + function isStartOfExpression(): boolean { + if (isStartOfLeftHandSideExpression()) { + return true; + } + + switch (token()) { + case SyntaxKind.PlusToken: + case SyntaxKind.MinusToken: + case SyntaxKind.TildeToken: + case SyntaxKind.ExclamationToken: + case SyntaxKind.DeleteKeyword: + case SyntaxKind.TypeOfKeyword: + case SyntaxKind.VoidKeyword: + case SyntaxKind.PlusPlusToken: + case SyntaxKind.MinusMinusToken: + case SyntaxKind.LessThanToken: + case SyntaxKind.AwaitKeyword: + case SyntaxKind.YieldKeyword: + // Yield/await always starts an expression. Either it is an identifier (in which case + // it is definitely an expression). Or it's a keyword (either because we're in + // a generator or async function, or in strict mode (or both)) and it started a yield or await expression. + return true; + default: + // Error tolerance. If we see the start of some binary operator, we consider + // that the start of an expression. That way we'll parse out a missing identifier, + // give a good message about an identifier being missing, and then consume the + // rest of the binary expression. + if (isBinaryOperator()) { + return true; + } + + return isIdentifier(); + } + } + + function isStartOfExpressionStatement(): boolean { + // As per the grammar, none of '{' or 'function' or 'class' can start an expression statement. + return token() !== SyntaxKind.OpenBraceToken && + token() !== SyntaxKind.FunctionKeyword && + token() !== SyntaxKind.ClassKeyword && + token() !== SyntaxKind.AtToken && + isStartOfExpression(); + } + + function parseExpression(): Expression { + // Expression[in]: + // AssignmentExpression[in] + // Expression[in] , AssignmentExpression[in] + + // clear the decorator context when parsing Expression, as it should be unambiguous when parsing a decorator + const saveDecoratorContext = inDecoratorContext(); + if (saveDecoratorContext) { + setDecoratorContext(/*val*/ false); + } + + let expr = parseAssignmentExpressionOrHigher(); + let operatorToken: BinaryOperatorToken; + while ((operatorToken = parseOptionalToken(SyntaxKind.CommaToken))) { + expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher()); + } + + if (saveDecoratorContext) { + setDecoratorContext(/*val*/ true); + } + return expr; + } + + function parseInitializer(): Expression | undefined { + return parseOptional(SyntaxKind.EqualsToken) ? parseAssignmentExpressionOrHigher() : undefined; + } + + function parseAssignmentExpressionOrHigher(): Expression { + // AssignmentExpression[in,yield]: + // 1) ConditionalExpression[?in,?yield] + // 2) LeftHandSideExpression = AssignmentExpression[?in,?yield] + // 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield] + // 4) ArrowFunctionExpression[?in,?yield] + // 5) AsyncArrowFunctionExpression[in,yield,await] + // 6) [+Yield] YieldExpression[?In] + // + // Note: for ease of implementation we treat productions '2' and '3' as the same thing. + // (i.e. they're both BinaryExpressions with an assignment operator in it). + + // First, do the simple check if we have a YieldExpression (production '6'). + if (isYieldExpression()) { + return parseYieldExpression(); + } + + // Then, check if we have an arrow function (production '4' and '5') that starts with a parenthesized + // parameter list or is an async arrow function. + // AsyncArrowFunctionExpression: + // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In] + // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In] + // Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression". + // And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression". + // + // If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is + // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done + // with AssignmentExpression if we see one. + const arrowExpression = tryParseParenthesizedArrowFunctionExpression() || tryParseAsyncSimpleArrowFunctionExpression(); + if (arrowExpression) { + return arrowExpression; + } + + // Now try to see if we're in production '1', '2' or '3'. A conditional expression can + // start with a LogicalOrExpression, while the assignment productions can only start with + // LeftHandSideExpressions. + // + // So, first, we try to just parse out a BinaryExpression. If we get something that is a + // LeftHandSide or higher, then we can try to parse out the assignment expression part. + // Otherwise, we try to parse out the conditional expression bit. We want to allow any + // binary expression here, so we pass in the 'lowest' precedence here so that it matches + // and consumes anything. + const expr = parseBinaryExpressionOrHigher(/*precedence*/ 0); + + // To avoid a look-ahead, we did not handle the case of an arrow function with a single un-parenthesized + // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single + // identifier and the current token is an arrow. + if (expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) { + return parseSimpleArrowFunctionExpression(expr); + } + + // Now see if we might be in cases '2' or '3'. + // If the expression was a LHS expression, and we have an assignment operator, then + // we're in '2' or '3'. Consume the assignment and return. + // + // Note: we call reScanGreaterToken so that we get an appropriately merged token + // for cases like `> > =` becoming `>>=` + if (isLeftHandSideExpression(expr) && isAssignmentOperator(reScanGreaterToken())) { + return makeBinaryExpression(expr, parseTokenNode(), parseAssignmentExpressionOrHigher()); + } + + // It wasn't an assignment or a lambda. This is a conditional expression: + return parseConditionalExpressionRest(expr); + } + + function isYieldExpression(): boolean { + if (token() === SyntaxKind.YieldKeyword) { + // If we have a 'yield' keyword, and this is a context where yield expressions are + // allowed, then definitely parse out a yield expression. + if (inYieldContext()) { + return true; + } + + // We're in a context where 'yield expr' is not allowed. However, if we can + // definitely tell that the user was trying to parse a 'yield expr' and not + // just a normal expr that start with a 'yield' identifier, then parse out + // a 'yield expr'. We can then report an error later that they are only + // allowed in generator expressions. + // + // for example, if we see 'yield(foo)', then we'll have to treat that as an + // invocation expression of something called 'yield'. However, if we have + // 'yield foo' then that is not legal as a normal expression, so we can + // definitely recognize this as a yield expression. + // + // for now we just check if the next token is an identifier. More heuristics + // can be added here later as necessary. We just need to make sure that we + // don't accidentally consume something legal. + return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine); + } + + return false; + } + + function nextTokenIsIdentifierOnSameLine() { + nextToken(); + return !scanner.hasPrecedingLineBreak() && isIdentifier(); + } + + function parseYieldExpression(): YieldExpression { + const node = createNode(SyntaxKind.YieldExpression); + + // YieldExpression[In] : + // yield + // yield [no LineTerminator here] [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] + // yield [no LineTerminator here] * [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] + nextToken(); + + if (!scanner.hasPrecedingLineBreak() && + (token() === SyntaxKind.AsteriskToken || isStartOfExpression())) { + node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); + node.expression = parseAssignmentExpressionOrHigher(); + return finishNode(node); + } + else { + // if the next token is not on the same line as yield. or we don't have an '*' or + // the start of an expression, then this is just a simple "yield" expression. + return finishNode(node); + } + } + + function parseSimpleArrowFunctionExpression(identifier: Identifier, asyncModifier?: NodeArray | undefined): ArrowFunction { + Debug.assert(token() === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>"); + + let node: ArrowFunction; + if (asyncModifier) { + node = createNode(SyntaxKind.ArrowFunction, asyncModifier.pos); + node.modifiers = asyncModifier; + } + else { + node = createNode(SyntaxKind.ArrowFunction, identifier.pos); + } + + const parameter = createNode(SyntaxKind.Parameter, identifier.pos); + parameter.name = identifier; + finishNode(parameter); + + node.parameters = createNodeArray([parameter], parameter.pos, parameter.end); + + node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken); + node.body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier); + + return addJSDocComment(finishNode(node)); + } + + function tryParseParenthesizedArrowFunctionExpression(): Expression | undefined { + const triState = isParenthesizedArrowFunctionExpression(); + if (triState === Tristate.False) { + // It's definitely not a parenthesized arrow function expression. + return undefined; + } + + // If we definitely have an arrow function, then we can just parse one, not requiring a + // following => or { token. Otherwise, we *might* have an arrow function. Try to parse + // it out, but don't allow any ambiguity, and return 'undefined' if this could be an + // expression instead. + const arrowFunction = triState === Tristate.True + ? parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ true) + : tryParse(parsePossibleParenthesizedArrowFunctionExpressionHead); + + if (!arrowFunction) { + // Didn't appear to actually be a parenthesized arrow function. Just bail out. + return undefined; + } + + const isAsync = hasModifier(arrowFunction, ModifierFlags.Async); + + // If we have an arrow, then try to parse the body. Even if not, try to parse if we + // have an opening brace, just in case we're in an error state. + const lastToken = token(); + arrowFunction.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken); + arrowFunction.body = (lastToken === SyntaxKind.EqualsGreaterThanToken || lastToken === SyntaxKind.OpenBraceToken) + ? parseArrowFunctionExpressionBody(isAsync) + : parseIdentifier(); + + return finishNode(arrowFunction); + } + + // True -> We definitely expect a parenthesized arrow function here. + // False -> There *cannot* be a parenthesized arrow function here. + // Unknown -> There *might* be a parenthesized arrow function here. + // Speculatively look ahead to be sure, and rollback if not. + function isParenthesizedArrowFunctionExpression(): Tristate { + if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken || token() === SyntaxKind.AsyncKeyword) { + return lookAhead(isParenthesizedArrowFunctionExpressionWorker); + } + + if (token() === SyntaxKind.EqualsGreaterThanToken) { + // ERROR RECOVERY TWEAK: + // If we see a standalone => try to parse it as an arrow function expression as that's + // likely what the user intended to write. + return Tristate.True; + } + // Definitely not a parenthesized arrow function. + return Tristate.False; + } + + function isParenthesizedArrowFunctionExpressionWorker() { + if (token() === SyntaxKind.AsyncKeyword) { + nextToken(); + if (scanner.hasPrecedingLineBreak()) { + return Tristate.False; + } + if (token() !== SyntaxKind.OpenParenToken && token() !== SyntaxKind.LessThanToken) { + return Tristate.False; + } + } + + const first = token(); + const second = nextToken(); + + if (first === SyntaxKind.OpenParenToken) { + if (second === SyntaxKind.CloseParenToken) { + // Simple cases: "() =>", "(): ", and "() {". + // This is an arrow function with no parameters. + // The last one is not actually an arrow function, + // but this is probably what the user intended. + const third = nextToken(); + switch (third) { + case SyntaxKind.EqualsGreaterThanToken: + case SyntaxKind.ColonToken: + case SyntaxKind.OpenBraceToken: + return Tristate.True; + default: + return Tristate.False; + } + } + + // If encounter "([" or "({", this could be the start of a binding pattern. + // Examples: + // ([ x ]) => { } + // ({ x }) => { } + // ([ x ]) + // ({ x }) + if (second === SyntaxKind.OpenBracketToken || second === SyntaxKind.OpenBraceToken) { + return Tristate.Unknown; + } + + // Simple case: "(..." + // This is an arrow function with a rest parameter. + if (second === SyntaxKind.DotDotDotToken) { + return Tristate.True; + } + + // Check for "(xxx yyy", where xxx is a modifier and yyy is an identifier. This + // isn't actually allowed, but we want to treat it as a lambda so we can provide + // a good error message. + if (isModifierKind(second) && second !== SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsIdentifier)) { + return Tristate.True; + } + + // If we had "(" followed by something that's not an identifier, + // then this definitely doesn't look like a lambda. "this" is not + // valid, but we want to parse it and then give a semantic error. + if (!isIdentifier() && second !== SyntaxKind.ThisKeyword) { + return Tristate.False; + } + + switch (nextToken()) { + case SyntaxKind.ColonToken: + // If we have something like "(a:", then we must have a + // type-annotated parameter in an arrow function expression. + return Tristate.True; + case SyntaxKind.QuestionToken: + nextToken(); + // If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lambda. + if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken) { + return Tristate.True; + } + // Otherwise it is definitely not a lambda. + return Tristate.False; + case SyntaxKind.CommaToken: + case SyntaxKind.EqualsToken: + case SyntaxKind.CloseParenToken: + // If we have "(a," or "(a=" or "(a)" this *could* be an arrow function + return Tristate.Unknown; + } + // It is definitely not an arrow function + return Tristate.False; + } + else { + Debug.assert(first === SyntaxKind.LessThanToken); + + // If we have "<" not followed by an identifier, + // then this definitely is not an arrow function. + if (!isIdentifier()) { + return Tristate.False; + } + + // JSX overrides + if (sourceFile.languageVariant === LanguageVariant.JSX) { + const isArrowFunctionInJsx = lookAhead(() => { + const third = nextToken(); + if (third === SyntaxKind.ExtendsKeyword) { + const fourth = nextToken(); + switch (fourth) { + case SyntaxKind.EqualsToken: + case SyntaxKind.GreaterThanToken: + return false; + default: + return true; + } + } + else if (third === SyntaxKind.CommaToken) { + return true; + } + return false; + }); + + if (isArrowFunctionInJsx) { + return Tristate.True; + } + + return Tristate.False; + } + + // This *could* be a parenthesized arrow function. + return Tristate.Unknown; + } + } + + function parsePossibleParenthesizedArrowFunctionExpressionHead(): ArrowFunction | undefined { + return parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ false); + } + + function tryParseAsyncSimpleArrowFunctionExpression(): ArrowFunction | undefined { + // We do a check here so that we won't be doing unnecessarily call to "lookAhead" + if (token() === SyntaxKind.AsyncKeyword) { + if (lookAhead(isUnParenthesizedAsyncArrowFunctionWorker) === Tristate.True) { + const asyncModifier = parseModifiersForArrowFunction(); + const expr = parseBinaryExpressionOrHigher(/*precedence*/ 0); + return parseSimpleArrowFunctionExpression(expr, asyncModifier); + } + } + return undefined; + } + + function isUnParenthesizedAsyncArrowFunctionWorker(): Tristate { + // AsyncArrowFunctionExpression: + // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In] + // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In] + if (token() === SyntaxKind.AsyncKeyword) { + nextToken(); + // If the "async" is followed by "=>" token then it is not a beginning of an async arrow-function + // but instead a simple arrow-function which will be parsed inside "parseAssignmentExpressionOrHigher" + if (scanner.hasPrecedingLineBreak() || token() === SyntaxKind.EqualsGreaterThanToken) { + return Tristate.False; + } + // Check for un-parenthesized AsyncArrowFunction + const expr = parseBinaryExpressionOrHigher(/*precedence*/ 0); + if (!scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) { + return Tristate.True; + } + } + + return Tristate.False; + } + + function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction | undefined { + const node = createNodeWithJSDoc(SyntaxKind.ArrowFunction); + node.modifiers = parseModifiersForArrowFunction(); + const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None; + // Arrow functions are never generators. + // + // If we're speculatively parsing a signature for a parenthesized arrow function, then + // we have to have a complete parameter list. Otherwise we might see something like + // a => (b => c) + // And think that "(b =>" was actually a parenthesized arrow function with a missing + // close paren. + if (!fillSignature(SyntaxKind.ColonToken, isAsync, node) && !allowAmbiguity) { + return undefined; + } + + // Parsing a signature isn't enough. + // Parenthesized arrow signatures often look like other valid expressions. + // For instance: + // - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value. + // - "(x,y)" is a comma expression parsed as a signature with two parameters. + // - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation. + // + // So we need just a bit of lookahead to ensure that it can only be a signature. + if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && token() !== SyntaxKind.OpenBraceToken) { + // Returning undefined here will cause our caller to rewind to where we started from. + return undefined; + } + + return node; + } + + function parseArrowFunctionExpressionBody(isAsync: boolean): Block | Expression { + if (token() === SyntaxKind.OpenBraceToken) { + return parseFunctionBlock(isAsync ? SignatureFlags.Await : SignatureFlags.None); + } + + if (token() !== SyntaxKind.SemicolonToken && + token() !== SyntaxKind.FunctionKeyword && + token() !== SyntaxKind.ClassKeyword && + isStartOfStatement() && + !isStartOfExpressionStatement()) { + // Check if we got a plain statement (i.e. no expression-statements, no function/class expressions/declarations) + // + // Here we try to recover from a potential error situation in the case where the + // user meant to supply a block. For example, if the user wrote: + // + // a => + // let v = 0; + // } + // + // they may be missing an open brace. Check to see if that's the case so we can + // try to recover better. If we don't do this, then the next close curly we see may end + // up preemptively closing the containing construct. + // + // Note: even when 'IgnoreMissingOpenBrace' is passed, parseBody will still error. + return parseFunctionBlock(SignatureFlags.IgnoreMissingOpenBrace | (isAsync ? SignatureFlags.Await : SignatureFlags.None)); + } + + return isAsync + ? doInAwaitContext(parseAssignmentExpressionOrHigher) + : doOutsideOfAwaitContext(parseAssignmentExpressionOrHigher); + } + + function parseConditionalExpressionRest(leftOperand: Expression): Expression { + // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher. + const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); + if (!questionToken) { + return leftOperand; + } + + // Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and + // we do not that for the 'whenFalse' part. + const node = createNode(SyntaxKind.ConditionalExpression, leftOperand.pos); + node.condition = leftOperand; + node.questionToken = questionToken; + node.whenTrue = doOutsideOfContext(disallowInAndDecoratorContext, parseAssignmentExpressionOrHigher); + node.colonToken = parseExpectedToken(SyntaxKind.ColonToken); + node.whenFalse = nodeIsPresent(node.colonToken) + ? parseAssignmentExpressionOrHigher() + : createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken)); + return finishNode(node); + } + + function parseBinaryExpressionOrHigher(precedence: number): Expression { + const leftOperand = parseUnaryExpressionOrHigher(); + return parseBinaryExpressionRest(precedence, leftOperand); + } + + function isInOrOfKeyword(t: SyntaxKind) { + return t === SyntaxKind.InKeyword || t === SyntaxKind.OfKeyword; + } + + function parseBinaryExpressionRest(precedence: number, leftOperand: Expression): Expression { + while (true) { + // We either have a binary operator here, or we're finished. We call + // reScanGreaterToken so that we merge token sequences like > and = into >= + + reScanGreaterToken(); + const newPrecedence = getBinaryOperatorPrecedence(token()); + + // Check the precedence to see if we should "take" this operator + // - For left associative operator (all operator but **), consume the operator, + // recursively call the function below, and parse binaryExpression as a rightOperand + // of the caller if the new precedence of the operator is greater then or equal to the current precedence. + // For example: + // a - b - c; + // ^token; leftOperand = b. Return b to the caller as a rightOperand + // a * b - c + // ^token; leftOperand = b. Return b to the caller as a rightOperand + // a - b * c; + // ^token; leftOperand = b. Return b * c to the caller as a rightOperand + // - For right associative operator (**), consume the operator, recursively call the function + // and parse binaryExpression as a rightOperand of the caller if the new precedence of + // the operator is strictly grater than the current precedence + // For example: + // a ** b ** c; + // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand + // a - b ** c; + // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand + // a ** b - c + // ^token; leftOperand = b. Return b to the caller as a rightOperand + const consumeCurrentOperator = token() === SyntaxKind.AsteriskAsteriskToken ? + newPrecedence >= precedence : + newPrecedence > precedence; + + if (!consumeCurrentOperator) { + break; + } + + if (token() === SyntaxKind.InKeyword && inDisallowInContext()) { + break; + } + + if (token() === SyntaxKind.AsKeyword) { + // Make sure we *do* perform ASI for constructs like this: + // var x = foo + // as (Bar) + // This should be parsed as an initialized variable, followed + // by a function call to 'as' with the argument 'Bar' + if (scanner.hasPrecedingLineBreak()) { + break; + } + else { + nextToken(); + leftOperand = makeAsExpression(leftOperand, parseType()); + } + } + else { + leftOperand = makeBinaryExpression(leftOperand, parseTokenNode(), parseBinaryExpressionOrHigher(newPrecedence)); + } + } + + return leftOperand; + } + + function isBinaryOperator() { + if (inDisallowInContext() && token() === SyntaxKind.InKeyword) { + return false; + } + + return getBinaryOperatorPrecedence(token()) > 0; + } + + function makeBinaryExpression(left: Expression, operatorToken: BinaryOperatorToken, right: Expression): BinaryExpression { + const node = createNode(SyntaxKind.BinaryExpression, left.pos); + node.left = left; + node.operatorToken = operatorToken; + node.right = right; + return finishNode(node); + } + + function makeAsExpression(left: Expression, right: TypeNode): AsExpression { + const node = createNode(SyntaxKind.AsExpression, left.pos); + node.expression = left; + node.type = right; + return finishNode(node); + } + + function parsePrefixUnaryExpression() { + const node = createNode(SyntaxKind.PrefixUnaryExpression); + node.operator = token(); + nextToken(); + node.operand = parseSimpleUnaryExpression(); + + return finishNode(node); + } + + function parseDeleteExpression() { + const node = createNode(SyntaxKind.DeleteExpression); + nextToken(); + node.expression = parseSimpleUnaryExpression(); + return finishNode(node); + } + + function parseTypeOfExpression() { + const node = createNode(SyntaxKind.TypeOfExpression); + nextToken(); + node.expression = parseSimpleUnaryExpression(); + return finishNode(node); + } + + function parseVoidExpression() { + const node = createNode(SyntaxKind.VoidExpression); + nextToken(); + node.expression = parseSimpleUnaryExpression(); + return finishNode(node); + } + + function isAwaitExpression(): boolean { + if (token() === SyntaxKind.AwaitKeyword) { + if (inAwaitContext()) { + return true; + } + + // here we are using similar heuristics as 'isYieldExpression' + return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine); + } + + return false; + } + + function parseAwaitExpression() { + const node = createNode(SyntaxKind.AwaitExpression); + nextToken(); + node.expression = parseSimpleUnaryExpression(); + return finishNode(node); + } + + /** + * Parse ES7 exponential expression and await expression + * + * ES7 ExponentiationExpression: + * 1) UnaryExpression[?Yield] + * 2) UpdateExpression[?Yield] ** ExponentiationExpression[?Yield] + * + */ + function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression { + /** + * ES7 UpdateExpression: + * 1) LeftHandSideExpression[?Yield] + * 2) LeftHandSideExpression[?Yield][no LineTerminator here]++ + * 3) LeftHandSideExpression[?Yield][no LineTerminator here]-- + * 4) ++UnaryExpression[?Yield] + * 5) --UnaryExpression[?Yield] + */ + if (isUpdateExpression()) { + const updateExpression = parseUpdateExpression(); + return token() === SyntaxKind.AsteriskAsteriskToken ? + parseBinaryExpressionRest(getBinaryOperatorPrecedence(token()), updateExpression) : + updateExpression; + } + + /** + * ES7 UnaryExpression: + * 1) UpdateExpression[?yield] + * 2) delete UpdateExpression[?yield] + * 3) void UpdateExpression[?yield] + * 4) typeof UpdateExpression[?yield] + * 5) + UpdateExpression[?yield] + * 6) - UpdateExpression[?yield] + * 7) ~ UpdateExpression[?yield] + * 8) ! UpdateExpression[?yield] + */ + const unaryOperator = token(); + const simpleUnaryExpression = parseSimpleUnaryExpression(); + if (token() === SyntaxKind.AsteriskAsteriskToken) { + const pos = skipTrivia(sourceText, simpleUnaryExpression.pos); + const { end } = simpleUnaryExpression; + if (simpleUnaryExpression.kind === SyntaxKind.TypeAssertionExpression) { + parseErrorAt(pos, end, Diagnostics.A_type_assertion_expression_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses); + } + else { + parseErrorAt(pos, end, Diagnostics.An_unary_expression_with_the_0_operator_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses, tokenToString(unaryOperator)); + } + } + return simpleUnaryExpression; + } + + /** + * Parse ES7 simple-unary expression or higher: + * + * ES7 UnaryExpression: + * 1) UpdateExpression[?yield] + * 2) delete UnaryExpression[?yield] + * 3) void UnaryExpression[?yield] + * 4) typeof UnaryExpression[?yield] + * 5) + UnaryExpression[?yield] + * 6) - UnaryExpression[?yield] + * 7) ~ UnaryExpression[?yield] + * 8) ! UnaryExpression[?yield] + * 9) [+Await] await UnaryExpression[?yield] + */ + function parseSimpleUnaryExpression(): UnaryExpression { + switch (token()) { + case SyntaxKind.PlusToken: + case SyntaxKind.MinusToken: + case SyntaxKind.TildeToken: + case SyntaxKind.ExclamationToken: + return parsePrefixUnaryExpression(); + case SyntaxKind.DeleteKeyword: + return parseDeleteExpression(); + case SyntaxKind.TypeOfKeyword: + return parseTypeOfExpression(); + case SyntaxKind.VoidKeyword: + return parseVoidExpression(); + case SyntaxKind.LessThanToken: + // This is modified UnaryExpression grammar in TypeScript + // UnaryExpression (modified): + // < type > UnaryExpression + return parseTypeAssertion(); + case SyntaxKind.AwaitKeyword: + if (isAwaitExpression()) { + return parseAwaitExpression(); + } + // falls through + default: + return parseUpdateExpression(); + } + } + + /** + * Check if the current token can possibly be an ES7 increment expression. + * + * ES7 UpdateExpression: + * LeftHandSideExpression[?Yield] + * LeftHandSideExpression[?Yield][no LineTerminator here]++ + * LeftHandSideExpression[?Yield][no LineTerminator here]-- + * ++LeftHandSideExpression[?Yield] + * --LeftHandSideExpression[?Yield] + */ + function isUpdateExpression(): boolean { + // This function is called inside parseUnaryExpression to decide + // whether to call parseSimpleUnaryExpression or call parseUpdateExpression directly + switch (token()) { + case SyntaxKind.PlusToken: + case SyntaxKind.MinusToken: + case SyntaxKind.TildeToken: + case SyntaxKind.ExclamationToken: + case SyntaxKind.DeleteKeyword: + case SyntaxKind.TypeOfKeyword: + case SyntaxKind.VoidKeyword: + case SyntaxKind.AwaitKeyword: + return false; + case SyntaxKind.LessThanToken: + // If we are not in JSX context, we are parsing TypeAssertion which is an UnaryExpression + if (sourceFile.languageVariant !== LanguageVariant.JSX) { + return false; + } + // We are in JSX context and the token is part of JSXElement. + // falls through + default: + return true; + } + } + + /** + * Parse ES7 UpdateExpression. UpdateExpression is used instead of ES6's PostFixExpression. + * + * ES7 UpdateExpression[yield]: + * 1) LeftHandSideExpression[?yield] + * 2) LeftHandSideExpression[?yield] [[no LineTerminator here]]++ + * 3) LeftHandSideExpression[?yield] [[no LineTerminator here]]-- + * 4) ++LeftHandSideExpression[?yield] + * 5) --LeftHandSideExpression[?yield] + * In TypeScript (2), (3) are parsed as PostfixUnaryExpression. (4), (5) are parsed as PrefixUnaryExpression + */ + function parseUpdateExpression(): UpdateExpression { + if (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) { + const node = createNode(SyntaxKind.PrefixUnaryExpression); + node.operator = token(); + nextToken(); + node.operand = parseLeftHandSideExpressionOrHigher(); + return finishNode(node); + } + else if (sourceFile.languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan)) { + // JSXElement is part of primaryExpression + return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true); + } + + const expression = parseLeftHandSideExpressionOrHigher(); + + Debug.assert(isLeftHandSideExpression(expression)); + if ((token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) { + const node = createNode(SyntaxKind.PostfixUnaryExpression, expression.pos); + node.operand = expression; + node.operator = token(); + nextToken(); + return finishNode(node); + } + + return expression; + } + + function parseLeftHandSideExpressionOrHigher(): LeftHandSideExpression { + // Original Ecma: + // LeftHandSideExpression: See 11.2 + // NewExpression + // CallExpression + // + // Our simplification: + // + // LeftHandSideExpression: See 11.2 + // MemberExpression + // CallExpression + // + // See comment in parseMemberExpressionOrHigher on how we replaced NewExpression with + // MemberExpression to make our lives easier. + // + // to best understand the below code, it's important to see how CallExpression expands + // out into its own productions: + // + // CallExpression: + // MemberExpression Arguments + // CallExpression Arguments + // CallExpression[Expression] + // CallExpression.IdentifierName + // import (AssignmentExpression) + // super Arguments + // super.IdentifierName + // + // Because of the recursion in these calls, we need to bottom out first. There are three + // bottom out states we can run into: 1) We see 'super' which must start either of + // the last two CallExpression productions. 2) We see 'import' which must start import call. + // 3)we have a MemberExpression which either completes the LeftHandSideExpression, + // or starts the beginning of the first four CallExpression productions. + let expression: MemberExpression; + if (token() === SyntaxKind.ImportKeyword) { + if (lookAhead(nextTokenIsOpenParenOrLessThan)) { + // We don't want to eagerly consume all import keyword as import call expression so we look ahead to find "(" + // For example: + // var foo3 = require("subfolder + // import * as foo1 from "module-from-node + // We want this import to be a statement rather than import call expression + sourceFile.flags |= NodeFlags.PossiblyContainsDynamicImport; + expression = parseTokenNode(); + } + else if (lookAhead(nextTokenIsDot)) { + // This is an 'import.*' metaproperty (i.e. 'import.meta') + const fullStart = scanner.getStartPos(); + nextToken(); // advance past the 'import' + nextToken(); // advance past the dot + const node = createNode(SyntaxKind.MetaProperty, fullStart) as MetaProperty; + node.keywordToken = SyntaxKind.ImportKeyword; + node.name = parseIdentifierName(); + expression = finishNode(node); + + sourceFile.flags |= NodeFlags.PossiblyContainsImportMeta; + } + else { + expression = parseMemberExpressionOrHigher(); + } + } + else { + expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher(); + } + + // Now, we *may* be complete. However, we might have consumed the start of a + // CallExpression. As such, we need to consume the rest of it here to be complete. + return parseCallExpressionRest(expression); + } + + function parseMemberExpressionOrHigher(): MemberExpression { + // Note: to make our lives simpler, we decompose the NewExpression productions and + // place ObjectCreationExpression and FunctionExpression into PrimaryExpression. + // like so: + // + // PrimaryExpression : See 11.1 + // this + // Identifier + // Literal + // ArrayLiteral + // ObjectLiteral + // (Expression) + // FunctionExpression + // new MemberExpression Arguments? + // + // MemberExpression : See 11.2 + // PrimaryExpression + // MemberExpression[Expression] + // MemberExpression.IdentifierName + // + // CallExpression : See 11.2 + // MemberExpression + // CallExpression Arguments + // CallExpression[Expression] + // CallExpression.IdentifierName + // + // Technically this is ambiguous. i.e. CallExpression defines: + // + // CallExpression: + // CallExpression Arguments + // + // If you see: "new Foo()" + // + // Then that could be treated as a single ObjectCreationExpression, or it could be + // treated as the invocation of "new Foo". We disambiguate that in code (to match + // the original grammar) by making sure that if we see an ObjectCreationExpression + // we always consume arguments if they are there. So we treat "new Foo()" as an + // object creation only, and not at all as an invocation. Another way to think + // about this is that for every "new" that we see, we will consume an argument list if + // it is there as part of the *associated* object creation node. Any additional + // argument lists we see, will become invocation expressions. + // + // Because there are no other places in the grammar now that refer to FunctionExpression + // or ObjectCreationExpression, it is safe to push down into the PrimaryExpression + // production. + // + // Because CallExpression and MemberExpression are left recursive, we need to bottom out + // of the recursion immediately. So we parse out a primary expression to start with. + const expression = parsePrimaryExpression(); + return parseMemberExpressionRest(expression); + } + + function parseSuperExpression(): MemberExpression { + const expression = parseTokenNode(); + if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.DotToken || token() === SyntaxKind.OpenBracketToken) { + return expression; + } + + // If we have seen "super" it must be followed by '(' or '.'. + // If it wasn't then just try to parse out a '.' and report an error. + const node = createNode(SyntaxKind.PropertyAccessExpression, expression.pos); + node.expression = expression; + parseExpectedToken(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access); + node.name = parseRightSideOfDot(/*allowIdentifierNames*/ true); + return finishNode(node); + } + + function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean): JsxElement | JsxSelfClosingElement | JsxFragment { + const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext); + let result: JsxElement | JsxSelfClosingElement | JsxFragment; + if (opening.kind === SyntaxKind.JsxOpeningElement) { + const node = createNode(SyntaxKind.JsxElement, opening.pos); + node.openingElement = opening; + + node.children = parseJsxChildren(node.openingElement); + node.closingElement = parseJsxClosingElement(inExpressionContext); + + if (!tagNamesAreEquivalent(node.openingElement.tagName, node.closingElement.tagName)) { + parseErrorAtRange(node.closingElement, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(sourceText, node.openingElement.tagName)); + } + + result = finishNode(node); + } + else if (opening.kind === SyntaxKind.JsxOpeningFragment) { + const node = createNode(SyntaxKind.JsxFragment, opening.pos); + node.openingFragment = opening; + node.children = parseJsxChildren(node.openingFragment); + node.closingFragment = parseJsxClosingFragment(inExpressionContext); + + result = finishNode(node); + } + else { + Debug.assert(opening.kind === SyntaxKind.JsxSelfClosingElement); + // Nothing else to do for self-closing elements + result = opening; + } + + // If the user writes the invalid code '
' in an expression context (i.e. not wrapped in + // an enclosing tag), we'll naively try to parse ^ this as a 'less than' operator and the remainder of the tag + // as garbage, which will cause the formatter to badly mangle the JSX. Perform a speculative parse of a JSX + // element if we see a < token so that we can wrap it in a synthetic binary expression so the formatter + // does less damage and we can report a better error. + // Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios + // of one sort or another. + if (inExpressionContext && token() === SyntaxKind.LessThanToken) { + const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true)); + if (invalidElement) { + parseErrorAtCurrentToken(Diagnostics.JSX_expressions_must_have_one_parent_element); + const badNode = createNode(SyntaxKind.BinaryExpression, result.pos); + badNode.end = invalidElement.end; + badNode.left = result; + badNode.right = invalidElement; + badNode.operatorToken = createMissingNode(SyntaxKind.CommaToken, /*reportAtCurrentPosition*/ false, /*diagnosticMessage*/ undefined!); // TODO: GH#18217 + badNode.operatorToken.pos = badNode.operatorToken.end = badNode.right.pos; + return badNode; + } + } + + return result; + } + + function parseJsxText(): JsxText { + const node = createNode(SyntaxKind.JsxText); + node.containsOnlyWhiteSpaces = currentToken === SyntaxKind.JsxTextAllWhiteSpaces; + currentToken = scanner.scanJsxToken(); + return finishNode(node); + } + + function parseJsxChild(openingTag: JsxOpeningElement | JsxOpeningFragment, token: JsxTokenSyntaxKind): JsxChild | undefined { + switch (token) { + case SyntaxKind.EndOfFileToken: + // If we hit EOF, issue the error at the tag that lacks the closing element + // rather than at the end of the file (which is useless) + if (isJsxOpeningFragment(openingTag)) { + parseErrorAtRange(openingTag, Diagnostics.JSX_fragment_has_no_corresponding_closing_tag); + } + else { + parseErrorAtRange(openingTag.tagName, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTag.tagName)); + } + return undefined; + case SyntaxKind.LessThanSlashToken: + case SyntaxKind.ConflictMarkerTrivia: + return undefined; + case SyntaxKind.JsxText: + case SyntaxKind.JsxTextAllWhiteSpaces: + return parseJsxText(); + case SyntaxKind.OpenBraceToken: + return parseJsxExpression(/*inExpressionContext*/ false); + case SyntaxKind.LessThanToken: + return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ false); + default: + return Debug.assertNever(token); + } + } + + function parseJsxChildren(openingTag: JsxOpeningElement | JsxOpeningFragment): NodeArray { + const list = []; + const listPos = getNodePos(); + const saveParsingContext = parsingContext; + parsingContext |= 1 << ParsingContext.JsxChildren; + + while (true) { + const child = parseJsxChild(openingTag, currentToken = scanner.reScanJsxToken()); + if (!child) break; + list.push(child); + } + + parsingContext = saveParsingContext; + return createNodeArray(list, listPos); + } + + function parseJsxAttributes(): JsxAttributes { + const jsxAttributes = createNode(SyntaxKind.JsxAttributes); + jsxAttributes.properties = parseList(ParsingContext.JsxAttributes, parseJsxAttribute); + return finishNode(jsxAttributes); + } + + function parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment { + const fullStart = scanner.getStartPos(); + + parseExpected(SyntaxKind.LessThanToken); + + if (token() === SyntaxKind.GreaterThanToken) { + // See below for explanation of scanJsxText + const node: JsxOpeningFragment = createNode(SyntaxKind.JsxOpeningFragment, fullStart); + scanJsxText(); + return finishNode(node); + } + + const tagName = parseJsxElementName(); + const typeArguments = tryParseTypeArguments(); + const attributes = parseJsxAttributes(); + + let node: JsxOpeningLikeElement; + + if (token() === SyntaxKind.GreaterThanToken) { + // Closing tag, so scan the immediately-following text with the JSX scanning instead + // of regular scanning to avoid treating illegal characters (e.g. '#') as immediate + // scanning errors + node = createNode(SyntaxKind.JsxOpeningElement, fullStart); + scanJsxText(); + } + else { + parseExpected(SyntaxKind.SlashToken); + if (inExpressionContext) { + parseExpected(SyntaxKind.GreaterThanToken); + } + else { + parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false); + scanJsxText(); + } + node = createNode(SyntaxKind.JsxSelfClosingElement, fullStart); + } + + node.tagName = tagName; + node.typeArguments = typeArguments; + node.attributes = attributes; + + return finishNode(node); + } + + function parseJsxElementName(): JsxTagNameExpression { + scanJsxIdentifier(); + // JsxElement can have name in the form of + // propertyAccessExpression + // primaryExpression in the form of an identifier and "this" keyword + // We can't just simply use parseLeftHandSideExpressionOrHigher because then we will start consider class,function etc as a keyword + // We only want to consider "this" as a primaryExpression + let expression: JsxTagNameExpression = token() === SyntaxKind.ThisKeyword ? + parseTokenNode() : parseIdentifierName(); + while (parseOptional(SyntaxKind.DotToken)) { + const propertyAccess: JsxTagNamePropertyAccess = createNode(SyntaxKind.PropertyAccessExpression, expression.pos); + propertyAccess.expression = expression; + propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true); + expression = finishNode(propertyAccess); + } + return expression; + } + + function parseJsxExpression(inExpressionContext: boolean): JsxExpression | undefined { + const node = createNode(SyntaxKind.JsxExpression); + + if (!parseExpected(SyntaxKind.OpenBraceToken)) { + return undefined; + } + + if (token() !== SyntaxKind.CloseBraceToken) { + node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); + node.expression = parseAssignmentExpressionOrHigher(); + } + if (inExpressionContext) { + parseExpected(SyntaxKind.CloseBraceToken); + } + else { + parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false); + scanJsxText(); + } + + return finishNode(node); + } + + function parseJsxAttribute(): JsxAttribute | JsxSpreadAttribute { + if (token() === SyntaxKind.OpenBraceToken) { + return parseJsxSpreadAttribute(); + } + + scanJsxIdentifier(); + const node = createNode(SyntaxKind.JsxAttribute); + node.name = parseIdentifierName(); + if (token() === SyntaxKind.EqualsToken) { + switch (scanJsxAttributeValue()) { + case SyntaxKind.StringLiteral: + node.initializer = parseLiteralNode(); + break; + default: + node.initializer = parseJsxExpression(/*inExpressionContext*/ true); + break; + } + } + return finishNode(node); + } + + function parseJsxSpreadAttribute(): JsxSpreadAttribute { + const node = createNode(SyntaxKind.JsxSpreadAttribute); + parseExpected(SyntaxKind.OpenBraceToken); + parseExpected(SyntaxKind.DotDotDotToken); + node.expression = parseExpression(); + parseExpected(SyntaxKind.CloseBraceToken); + return finishNode(node); + } + + function parseJsxClosingElement(inExpressionContext: boolean): JsxClosingElement { + const node = createNode(SyntaxKind.JsxClosingElement); + parseExpected(SyntaxKind.LessThanSlashToken); + node.tagName = parseJsxElementName(); + if (inExpressionContext) { + parseExpected(SyntaxKind.GreaterThanToken); + } + else { + parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false); + scanJsxText(); + } + return finishNode(node); + } + + function parseJsxClosingFragment(inExpressionContext: boolean): JsxClosingFragment { + const node = createNode(SyntaxKind.JsxClosingFragment); + parseExpected(SyntaxKind.LessThanSlashToken); + if (tokenIsIdentifierOrKeyword(token())) { + parseErrorAtRange(parseJsxElementName(), Diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment); + } + if (inExpressionContext) { + parseExpected(SyntaxKind.GreaterThanToken); + } + else { + parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false); + scanJsxText(); + } + return finishNode(node); + } + + function parseTypeAssertion(): TypeAssertion { + const node = createNode(SyntaxKind.TypeAssertionExpression); + parseExpected(SyntaxKind.LessThanToken); + node.type = parseType(); + parseExpected(SyntaxKind.GreaterThanToken); + node.expression = parseSimpleUnaryExpression(); + return finishNode(node); + } + + function parseMemberExpressionRest(expression: LeftHandSideExpression): MemberExpression { + while (true) { + const dotToken = parseOptionalToken(SyntaxKind.DotToken); + if (dotToken) { + const propertyAccess = createNode(SyntaxKind.PropertyAccessExpression, expression.pos); + propertyAccess.expression = expression; + propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true); + expression = finishNode(propertyAccess); + continue; + } + + if (token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { + nextToken(); + const nonNullExpression = createNode(SyntaxKind.NonNullExpression, expression.pos); + nonNullExpression.expression = expression; + expression = finishNode(nonNullExpression); + continue; + } + + // when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName + if (!inDecoratorContext() && parseOptional(SyntaxKind.OpenBracketToken)) { + const indexedAccess = createNode(SyntaxKind.ElementAccessExpression, expression.pos); + indexedAccess.expression = expression; + + if (token() === SyntaxKind.CloseBracketToken) { + indexedAccess.argumentExpression = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.An_element_access_expression_should_take_an_argument); + } + else { + const argument = allowInAnd(parseExpression); + if (isStringOrNumericLiteralLike(argument)) { + argument.text = internIdentifier(argument.text); + } + indexedAccess.argumentExpression = argument; + } + + parseExpected(SyntaxKind.CloseBracketToken); + expression = finishNode(indexedAccess); + continue; + } + + if (isTemplateStartOfTaggedTemplate()) { + expression = parseTaggedTemplateRest(expression, /*typeArguments*/ undefined); + continue; + } + + return expression; + } + } + + function isTemplateStartOfTaggedTemplate() { + return token() === SyntaxKind.NoSubstitutionTemplateLiteral || token() === SyntaxKind.TemplateHead; + } + + function parseTaggedTemplateRest(tag: LeftHandSideExpression, typeArguments: NodeArray | undefined) { + const tagExpression = createNode(SyntaxKind.TaggedTemplateExpression, tag.pos); + tagExpression.tag = tag; + tagExpression.typeArguments = typeArguments; + tagExpression.template = token() === SyntaxKind.NoSubstitutionTemplateLiteral + ? parseLiteralNode() + : parseTemplateExpression(); + return finishNode(tagExpression); + } + + function parseCallExpressionRest(expression: LeftHandSideExpression): LeftHandSideExpression { + while (true) { + expression = parseMemberExpressionRest(expression); + if (token() === SyntaxKind.LessThanToken) { + // See if this is the start of a generic invocation. If so, consume it and + // keep checking for postfix expressions. Otherwise, it's just a '<' that's + // part of an arithmetic expression. Break out so we consume it higher in the + // stack. + const typeArguments = tryParse(parseTypeArgumentsInExpression); + if (!typeArguments) { + return expression; + } + + if (isTemplateStartOfTaggedTemplate()) { + expression = parseTaggedTemplateRest(expression, typeArguments); + continue; + } + + const callExpr = createNode(SyntaxKind.CallExpression, expression.pos); + callExpr.expression = expression; + callExpr.typeArguments = typeArguments; + callExpr.arguments = parseArgumentList(); + expression = finishNode(callExpr); + continue; + } + else if (token() === SyntaxKind.OpenParenToken) { + const callExpr = createNode(SyntaxKind.CallExpression, expression.pos); + callExpr.expression = expression; + callExpr.arguments = parseArgumentList(); + expression = finishNode(callExpr); + continue; + } + + return expression; + } + } + + function parseArgumentList() { + parseExpected(SyntaxKind.OpenParenToken); + const result = parseDelimitedList(ParsingContext.ArgumentExpressions, parseArgumentExpression); + parseExpected(SyntaxKind.CloseParenToken); + return result; + } + + function parseTypeArgumentsInExpression() { + if (!parseOptional(SyntaxKind.LessThanToken)) { + return undefined; + } + + const typeArguments = parseDelimitedList(ParsingContext.TypeArguments, parseType); + if (!parseExpected(SyntaxKind.GreaterThanToken)) { + // If it doesn't have the closing `>` then it's definitely not an type argument list. + return undefined; + } + + // If we have a '<', then only parse this as a argument list if the type arguments + // are complete and we have an open paren. if we don't, rewind and return nothing. + return typeArguments && canFollowTypeArgumentsInExpression() + ? typeArguments + : undefined; + } + + function canFollowTypeArgumentsInExpression(): boolean { + switch (token()) { + case SyntaxKind.OpenParenToken: // foo( + case SyntaxKind.NoSubstitutionTemplateLiteral: // foo `...` + case SyntaxKind.TemplateHead: // foo `...${100}...` + // these are the only tokens can legally follow a type argument + // list. So we definitely want to treat them as type arg lists. + + case SyntaxKind.DotToken: // foo. + case SyntaxKind.CloseParenToken: // foo) + case SyntaxKind.CloseBracketToken: // foo] + case SyntaxKind.ColonToken: // foo: + case SyntaxKind.SemicolonToken: // foo; + case SyntaxKind.QuestionToken: // foo? + case SyntaxKind.EqualsEqualsToken: // foo == + case SyntaxKind.EqualsEqualsEqualsToken: // foo === + case SyntaxKind.ExclamationEqualsToken: // foo != + case SyntaxKind.ExclamationEqualsEqualsToken: // foo !== + case SyntaxKind.AmpersandAmpersandToken: // foo && + case SyntaxKind.BarBarToken: // foo || + case SyntaxKind.CaretToken: // foo ^ + case SyntaxKind.AmpersandToken: // foo & + case SyntaxKind.BarToken: // foo | + case SyntaxKind.CloseBraceToken: // foo } + case SyntaxKind.EndOfFileToken: // foo + // these cases can't legally follow a type arg list. However, they're not legal + // expressions either. The user is probably in the middle of a generic type. So + // treat it as such. + return true; + + case SyntaxKind.CommaToken: // foo, + case SyntaxKind.OpenBraceToken: // foo { + // We don't want to treat these as type arguments. Otherwise we'll parse this + // as an invocation expression. Instead, we want to parse out the expression + // in isolation from the type arguments. + + default: + // Anything else treat as an expression. + return false; + } + } + + function parsePrimaryExpression(): PrimaryExpression { + switch (token()) { + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + return parseLiteralNode(); + case SyntaxKind.ThisKeyword: + case SyntaxKind.SuperKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + return parseTokenNode(); + case SyntaxKind.OpenParenToken: + return parseParenthesizedExpression(); + case SyntaxKind.OpenBracketToken: + return parseArrayLiteralExpression(); + case SyntaxKind.OpenBraceToken: + return parseObjectLiteralExpression(); + case SyntaxKind.AsyncKeyword: + // Async arrow functions are parsed earlier in parseAssignmentExpressionOrHigher. + // If we encounter `async [no LineTerminator here] function` then this is an async + // function; otherwise, its an identifier. + if (!lookAhead(nextTokenIsFunctionKeywordOnSameLine)) { + break; + } + + return parseFunctionExpression(); + case SyntaxKind.ClassKeyword: + return parseClassExpression(); + case SyntaxKind.FunctionKeyword: + return parseFunctionExpression(); + case SyntaxKind.NewKeyword: + return parseNewExpressionOrNewDotTarget(); + case SyntaxKind.SlashToken: + case SyntaxKind.SlashEqualsToken: + if (reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) { + return parseLiteralNode(); + } + break; + case SyntaxKind.TemplateHead: + return parseTemplateExpression(); + } + + return parseIdentifier(Diagnostics.Expression_expected); + } + + function parseParenthesizedExpression(): ParenthesizedExpression { + const node = createNodeWithJSDoc(SyntaxKind.ParenthesizedExpression); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.CloseParenToken); + return finishNode(node); + } + + function parseSpreadElement(): Expression { + const node = createNode(SyntaxKind.SpreadElement); + parseExpected(SyntaxKind.DotDotDotToken); + node.expression = parseAssignmentExpressionOrHigher(); + return finishNode(node); + } + + function parseArgumentOrArrayLiteralElement(): Expression { + return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() : + token() === SyntaxKind.CommaToken ? createNode(SyntaxKind.OmittedExpression) : + parseAssignmentExpressionOrHigher(); + } + + function parseArgumentExpression(): Expression { + return doOutsideOfContext(disallowInAndDecoratorContext, parseArgumentOrArrayLiteralElement); + } + + function parseArrayLiteralExpression(): ArrayLiteralExpression { + const node = createNode(SyntaxKind.ArrayLiteralExpression); + parseExpected(SyntaxKind.OpenBracketToken); + if (scanner.hasPrecedingLineBreak()) { + node.multiLine = true; + } + node.elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement); + parseExpected(SyntaxKind.CloseBracketToken); + return finishNode(node); + } + + function parseObjectLiteralElement(): ObjectLiteralElementLike { + const node = createNodeWithJSDoc(SyntaxKind.Unknown); + + if (parseOptionalToken(SyntaxKind.DotDotDotToken)) { + node.kind = SyntaxKind.SpreadAssignment; + (node).expression = parseAssignmentExpressionOrHigher(); + return finishNode(node); + } + + node.decorators = parseDecorators(); + node.modifiers = parseModifiers(); + + if (parseContextualModifier(SyntaxKind.GetKeyword)) { + return parseAccessorDeclaration(node, SyntaxKind.GetAccessor); + } + if (parseContextualModifier(SyntaxKind.SetKeyword)) { + return parseAccessorDeclaration(node, SyntaxKind.SetAccessor); + } + + const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); + const tokenIsIdentifier = isIdentifier(); + node.name = parsePropertyName(); + // Disallowing of optional property assignments happens in the grammar checker. + (node).questionToken = parseOptionalToken(SyntaxKind.QuestionToken); + if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { + return parseMethodDeclaration(node, asteriskToken); + } + + // check if it is short-hand property assignment or normal property assignment + // NOTE: if token is EqualsToken it is interpreted as CoverInitializedName production + // CoverInitializedName[Yield] : + // IdentifierReference[?Yield] Initializer[In, ?Yield] + // this is necessary because ObjectLiteral productions are also used to cover grammar for ObjectAssignmentPattern + const isShorthandPropertyAssignment = + tokenIsIdentifier && (token() === SyntaxKind.CommaToken || token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EqualsToken); + if (isShorthandPropertyAssignment) { + node.kind = SyntaxKind.ShorthandPropertyAssignment; + const equalsToken = parseOptionalToken(SyntaxKind.EqualsToken); + if (equalsToken) { + (node).equalsToken = equalsToken; + (node).objectAssignmentInitializer = allowInAnd(parseAssignmentExpressionOrHigher); + } + } + else { + node.kind = SyntaxKind.PropertyAssignment; + parseExpected(SyntaxKind.ColonToken); + (node).initializer = allowInAnd(parseAssignmentExpressionOrHigher); + } + return finishNode(node); + } + + function parseObjectLiteralExpression(): ObjectLiteralExpression { + const node = createNode(SyntaxKind.ObjectLiteralExpression); + parseExpected(SyntaxKind.OpenBraceToken); + if (scanner.hasPrecedingLineBreak()) { + node.multiLine = true; + } + + node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimiter*/ true); + parseExpected(SyntaxKind.CloseBraceToken); + return finishNode(node); + } + + function parseFunctionExpression(): FunctionExpression { + // GeneratorExpression: + // function* BindingIdentifier [Yield][opt](FormalParameters[Yield]){ GeneratorBody } + // + // FunctionExpression: + // function BindingIdentifier[opt](FormalParameters){ FunctionBody } + const saveDecoratorContext = inDecoratorContext(); + if (saveDecoratorContext) { + setDecoratorContext(/*val*/ false); + } + + const node = createNodeWithJSDoc(SyntaxKind.FunctionExpression); + node.modifiers = parseModifiers(); + parseExpected(SyntaxKind.FunctionKeyword); + node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); + + const isGenerator = node.asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; + const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None; + node.name = + isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalIdentifier) : + isGenerator ? doInYieldContext(parseOptionalIdentifier) : + isAsync ? doInAwaitContext(parseOptionalIdentifier) : + parseOptionalIdentifier(); + + fillSignature(SyntaxKind.ColonToken, isGenerator | isAsync, node); + node.body = parseFunctionBlock(isGenerator | isAsync); + + if (saveDecoratorContext) { + setDecoratorContext(/*val*/ true); + } + + return finishNode(node); + } + + function parseOptionalIdentifier(): Identifier | undefined { + return isIdentifier() ? parseIdentifier() : undefined; + } + + function parseNewExpressionOrNewDotTarget(): NewExpression | MetaProperty { + const fullStart = scanner.getStartPos(); + parseExpected(SyntaxKind.NewKeyword); + if (parseOptional(SyntaxKind.DotToken)) { + const node = createNode(SyntaxKind.MetaProperty, fullStart); + node.keywordToken = SyntaxKind.NewKeyword; + node.name = parseIdentifierName(); + return finishNode(node); + } + + let expression: MemberExpression = parsePrimaryExpression(); + let typeArguments; + while (true) { + expression = parseMemberExpressionRest(expression); + typeArguments = tryParse(parseTypeArgumentsInExpression); + if (isTemplateStartOfTaggedTemplate()) { + Debug.assert(!!typeArguments, + "Expected a type argument list; all plain tagged template starts should be consumed in 'parseMemberExpressionRest'"); + expression = parseTaggedTemplateRest(expression, typeArguments); + typeArguments = undefined; + } + break; + } + + const node = createNode(SyntaxKind.NewExpression, fullStart); + node.expression = expression; + node.typeArguments = typeArguments; + if (node.typeArguments || token() === SyntaxKind.OpenParenToken) { + node.arguments = parseArgumentList(); + } + return finishNode(node); + } + + // STATEMENTS + function parseBlock(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block { + const node = createNode(SyntaxKind.Block); + if (parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage) || ignoreMissingOpenBrace) { + if (scanner.hasPrecedingLineBreak()) { + node.multiLine = true; + } + + node.statements = parseList(ParsingContext.BlockStatements, parseStatement); + parseExpected(SyntaxKind.CloseBraceToken); + } + else { + node.statements = createMissingList(); + } + return finishNode(node); + } + + function parseFunctionBlock(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block { + const savedYieldContext = inYieldContext(); + setYieldContext(!!(flags & SignatureFlags.Yield)); + + const savedAwaitContext = inAwaitContext(); + setAwaitContext(!!(flags & SignatureFlags.Await)); + + // We may be in a [Decorator] context when parsing a function expression or + // arrow function. The body of the function is not in [Decorator] context. + const saveDecoratorContext = inDecoratorContext(); + if (saveDecoratorContext) { + setDecoratorContext(/*val*/ false); + } + + const block = parseBlock(!!(flags & SignatureFlags.IgnoreMissingOpenBrace), diagnosticMessage); + + if (saveDecoratorContext) { + setDecoratorContext(/*val*/ true); + } + + setYieldContext(savedYieldContext); + setAwaitContext(savedAwaitContext); + + return block; + } + + function parseEmptyStatement(): Statement { + const node = createNode(SyntaxKind.EmptyStatement); + parseExpected(SyntaxKind.SemicolonToken); + return finishNode(node); + } + + function parseIfStatement(): IfStatement { + const node = createNode(SyntaxKind.IfStatement); + parseExpected(SyntaxKind.IfKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.CloseParenToken); + node.thenStatement = parseStatement(); + node.elseStatement = parseOptional(SyntaxKind.ElseKeyword) ? parseStatement() : undefined; + return finishNode(node); + } + + function parseDoStatement(): DoStatement { + const node = createNode(SyntaxKind.DoStatement); + parseExpected(SyntaxKind.DoKeyword); + node.statement = parseStatement(); + parseExpected(SyntaxKind.WhileKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.CloseParenToken); + + // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html + // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in + // spec but allowed in consensus reality. Approved -- this is the de-facto standard whereby + // do;while(0)x will have a semicolon inserted before x. + parseOptional(SyntaxKind.SemicolonToken); + return finishNode(node); + } + + function parseWhileStatement(): WhileStatement { + const node = createNode(SyntaxKind.WhileStatement); + parseExpected(SyntaxKind.WhileKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.CloseParenToken); + node.statement = parseStatement(); + return finishNode(node); + } + + function parseForOrForInOrForOfStatement(): Statement { + const pos = getNodePos(); + parseExpected(SyntaxKind.ForKeyword); + const awaitToken = parseOptionalToken(SyntaxKind.AwaitKeyword); + parseExpected(SyntaxKind.OpenParenToken); + + let initializer!: VariableDeclarationList | Expression; + if (token() !== SyntaxKind.SemicolonToken) { + if (token() === SyntaxKind.VarKeyword || token() === SyntaxKind.LetKeyword || token() === SyntaxKind.ConstKeyword) { + initializer = parseVariableDeclarationList(/*inForStatementInitializer*/ true); + } + else { + initializer = disallowInAnd(parseExpression); + } + } + let forOrForInOrForOfStatement: IterationStatement; + if (awaitToken ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) { + const forOfStatement = createNode(SyntaxKind.ForOfStatement, pos); + forOfStatement.awaitModifier = awaitToken; + forOfStatement.initializer = initializer; + forOfStatement.expression = allowInAnd(parseAssignmentExpressionOrHigher); + parseExpected(SyntaxKind.CloseParenToken); + forOrForInOrForOfStatement = forOfStatement; + } + else if (parseOptional(SyntaxKind.InKeyword)) { + const forInStatement = createNode(SyntaxKind.ForInStatement, pos); + forInStatement.initializer = initializer; + forInStatement.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.CloseParenToken); + forOrForInOrForOfStatement = forInStatement; + } + else { + const forStatement = createNode(SyntaxKind.ForStatement, pos); + forStatement.initializer = initializer; + parseExpected(SyntaxKind.SemicolonToken); + if (token() !== SyntaxKind.SemicolonToken && token() !== SyntaxKind.CloseParenToken) { + forStatement.condition = allowInAnd(parseExpression); + } + parseExpected(SyntaxKind.SemicolonToken); + if (token() !== SyntaxKind.CloseParenToken) { + forStatement.incrementor = allowInAnd(parseExpression); + } + parseExpected(SyntaxKind.CloseParenToken); + forOrForInOrForOfStatement = forStatement; + } + + forOrForInOrForOfStatement.statement = parseStatement(); + + return finishNode(forOrForInOrForOfStatement); + } + + function parseBreakOrContinueStatement(kind: SyntaxKind): BreakOrContinueStatement { + const node = createNode(kind); + + parseExpected(kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword); + if (!canParseSemicolon()) { + node.label = parseIdentifier(); + } + + parseSemicolon(); + return finishNode(node); + } + + function parseReturnStatement(): ReturnStatement { + const node = createNode(SyntaxKind.ReturnStatement); + + parseExpected(SyntaxKind.ReturnKeyword); + if (!canParseSemicolon()) { + node.expression = allowInAnd(parseExpression); + } + + parseSemicolon(); + return finishNode(node); + } + + function parseWithStatement(): WithStatement { + const node = createNode(SyntaxKind.WithStatement); + parseExpected(SyntaxKind.WithKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.CloseParenToken); + node.statement = doInsideOfContext(NodeFlags.InWithStatement, parseStatement); + return finishNode(node); + } + + function parseCaseClause(): CaseClause { + const node = createNode(SyntaxKind.CaseClause); + parseExpected(SyntaxKind.CaseKeyword); + node.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.ColonToken); + node.statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement); + return finishNode(node); + } + + function parseDefaultClause(): DefaultClause { + const node = createNode(SyntaxKind.DefaultClause); + parseExpected(SyntaxKind.DefaultKeyword); + parseExpected(SyntaxKind.ColonToken); + node.statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement); + return finishNode(node); + } + + function parseCaseOrDefaultClause(): CaseOrDefaultClause { + return token() === SyntaxKind.CaseKeyword ? parseCaseClause() : parseDefaultClause(); + } + + function parseSwitchStatement(): SwitchStatement { + const node = createNode(SyntaxKind.SwitchStatement); + parseExpected(SyntaxKind.SwitchKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = allowInAnd(parseExpression); + parseExpected(SyntaxKind.CloseParenToken); + const caseBlock = createNode(SyntaxKind.CaseBlock); + parseExpected(SyntaxKind.OpenBraceToken); + caseBlock.clauses = parseList(ParsingContext.SwitchClauses, parseCaseOrDefaultClause); + parseExpected(SyntaxKind.CloseBraceToken); + node.caseBlock = finishNode(caseBlock); + return finishNode(node); + } + + function parseThrowStatement(): ThrowStatement { + // ThrowStatement[Yield] : + // throw [no LineTerminator here]Expression[In, ?Yield]; + + // Because of automatic semicolon insertion, we need to report error if this + // throw could be terminated with a semicolon. Note: we can't call 'parseExpression' + // directly as that might consume an expression on the following line. + // We just return 'undefined' in that case. The actual error will be reported in the + // grammar walker. + const node = createNode(SyntaxKind.ThrowStatement); + parseExpected(SyntaxKind.ThrowKeyword); + node.expression = scanner.hasPrecedingLineBreak() ? undefined : allowInAnd(parseExpression); + parseSemicolon(); + return finishNode(node); + } + + // TODO: Review for error recovery + function parseTryStatement(): TryStatement { + const node = createNode(SyntaxKind.TryStatement); + + parseExpected(SyntaxKind.TryKeyword); + node.tryBlock = parseBlock(/*ignoreMissingOpenBrace*/ false); + node.catchClause = token() === SyntaxKind.CatchKeyword ? parseCatchClause() : undefined; + + // If we don't have a catch clause, then we must have a finally clause. Try to parse + // one out no matter what. + if (!node.catchClause || token() === SyntaxKind.FinallyKeyword) { + parseExpected(SyntaxKind.FinallyKeyword); + node.finallyBlock = parseBlock(/*ignoreMissingOpenBrace*/ false); + } + + return finishNode(node); + } + + function parseCatchClause(): CatchClause { + const result = createNode(SyntaxKind.CatchClause); + parseExpected(SyntaxKind.CatchKeyword); + + if (parseOptional(SyntaxKind.OpenParenToken)) { + result.variableDeclaration = parseVariableDeclaration(); + parseExpected(SyntaxKind.CloseParenToken); + } + else { + // Keep shape of node to avoid degrading performance. + result.variableDeclaration = undefined; + } + + result.block = parseBlock(/*ignoreMissingOpenBrace*/ false); + return finishNode(result); + } + + function parseDebuggerStatement(): Statement { + const node = createNode(SyntaxKind.DebuggerStatement); + parseExpected(SyntaxKind.DebuggerKeyword); + parseSemicolon(); + return finishNode(node); + } + + function parseExpressionOrLabeledStatement(): ExpressionStatement | LabeledStatement { + // Avoiding having to do the lookahead for a labeled statement by just trying to parse + // out an expression, seeing if it is identifier and then seeing if it is followed by + // a colon. + const node = createNodeWithJSDoc(SyntaxKind.Unknown); + const expression = allowInAnd(parseExpression); + if (expression.kind === SyntaxKind.Identifier && parseOptional(SyntaxKind.ColonToken)) { + node.kind = SyntaxKind.LabeledStatement; + (node).label = expression; + (node).statement = parseStatement(); + } + else { + node.kind = SyntaxKind.ExpressionStatement; + (node).expression = expression; + parseSemicolon(); + } + return finishNode(node); + } + + function nextTokenIsIdentifierOrKeywordOnSameLine() { + nextToken(); + return tokenIsIdentifierOrKeyword(token()) && !scanner.hasPrecedingLineBreak(); + } + + function nextTokenIsClassKeywordOnSameLine() { + nextToken(); + return token() === SyntaxKind.ClassKeyword && !scanner.hasPrecedingLineBreak(); + } + + function nextTokenIsFunctionKeywordOnSameLine() { + nextToken(); + return token() === SyntaxKind.FunctionKeyword && !scanner.hasPrecedingLineBreak(); + } + + function nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine() { + nextToken(); + return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak(); + } + + function isDeclaration(): boolean { + while (true) { + switch (token()) { + case SyntaxKind.VarKeyword: + case SyntaxKind.LetKeyword: + case SyntaxKind.ConstKeyword: + case SyntaxKind.FunctionKeyword: + case SyntaxKind.ClassKeyword: + case SyntaxKind.EnumKeyword: + return true; + + // 'declare', 'module', 'namespace', 'interface'* and 'type' are all legal JavaScript identifiers; + // however, an identifier cannot be followed by another identifier on the same line. This is what we + // count on to parse out the respective declarations. For instance, we exploit this to say that + // + // namespace n + // + // can be none other than the beginning of a namespace declaration, but need to respect that JavaScript sees + // + // namespace + // n + // + // as the identifier 'namespace' on one line followed by the identifier 'n' on another. + // We need to look one token ahead to see if it permissible to try parsing a declaration. + // + // *Note*: 'interface' is actually a strict mode reserved word. So while + // + // "use strict" + // interface + // I {} + // + // could be legal, it would add complexity for very little gain. + case SyntaxKind.InterfaceKeyword: + case SyntaxKind.TypeKeyword: + return nextTokenIsIdentifierOnSameLine(); + case SyntaxKind.ModuleKeyword: + case SyntaxKind.NamespaceKeyword: + return nextTokenIsIdentifierOrStringLiteralOnSameLine(); + case SyntaxKind.AbstractKeyword: + case SyntaxKind.AsyncKeyword: + case SyntaxKind.DeclareKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.PublicKeyword: + case SyntaxKind.ReadonlyKeyword: + nextToken(); + // ASI takes effect for this modifier. + if (scanner.hasPrecedingLineBreak()) { + return false; + } + continue; + + case SyntaxKind.GlobalKeyword: + nextToken(); + return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.Identifier || token() === SyntaxKind.ExportKeyword; + + case SyntaxKind.ImportKeyword: + nextToken(); + return token() === SyntaxKind.StringLiteral || token() === SyntaxKind.AsteriskToken || + token() === SyntaxKind.OpenBraceToken || tokenIsIdentifierOrKeyword(token()); + case SyntaxKind.ExportKeyword: + nextToken(); + if (token() === SyntaxKind.EqualsToken || token() === SyntaxKind.AsteriskToken || + token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.DefaultKeyword || + token() === SyntaxKind.AsKeyword) { + return true; + } + continue; + + case SyntaxKind.StaticKeyword: + nextToken(); + continue; + default: + return false; + } + } + } + + function isStartOfDeclaration(): boolean { + return lookAhead(isDeclaration); + } + + function isStartOfStatement(): boolean { + switch (token()) { + case SyntaxKind.AtToken: + case SyntaxKind.SemicolonToken: + case SyntaxKind.OpenBraceToken: + case SyntaxKind.VarKeyword: + case SyntaxKind.LetKeyword: + case SyntaxKind.FunctionKeyword: + case SyntaxKind.ClassKeyword: + case SyntaxKind.EnumKeyword: + case SyntaxKind.IfKeyword: + case SyntaxKind.DoKeyword: + case SyntaxKind.WhileKeyword: + case SyntaxKind.ForKeyword: + case SyntaxKind.ContinueKeyword: + case SyntaxKind.BreakKeyword: + case SyntaxKind.ReturnKeyword: + case SyntaxKind.WithKeyword: + case SyntaxKind.SwitchKeyword: + case SyntaxKind.ThrowKeyword: + case SyntaxKind.TryKeyword: + case SyntaxKind.DebuggerKeyword: + // 'catch' and 'finally' do not actually indicate that the code is part of a statement, + // however, we say they are here so that we may gracefully parse them and error later. + case SyntaxKind.CatchKeyword: + case SyntaxKind.FinallyKeyword: + return true; + + case SyntaxKind.ImportKeyword: + return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThanOrDot); + + case SyntaxKind.ConstKeyword: + case SyntaxKind.ExportKeyword: + return isStartOfDeclaration(); + + case SyntaxKind.AsyncKeyword: + case SyntaxKind.DeclareKeyword: + case SyntaxKind.InterfaceKeyword: + case SyntaxKind.ModuleKeyword: + case SyntaxKind.NamespaceKeyword: + case SyntaxKind.TypeKeyword: + case SyntaxKind.GlobalKeyword: + // When these don't start a declaration, they're an identifier in an expression statement + return true; + + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.StaticKeyword: + case SyntaxKind.ReadonlyKeyword: + // When these don't start a declaration, they may be the start of a class member if an identifier + // immediately follows. Otherwise they're an identifier in an expression statement. + return isStartOfDeclaration() || !lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine); + + default: + return isStartOfExpression(); + } + } + + function nextTokenIsIdentifierOrStartOfDestructuring() { + nextToken(); + return isIdentifier() || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken; + } + + function isLetDeclaration() { + // In ES6 'let' always starts a lexical declaration if followed by an identifier or { + // or [. + return lookAhead(nextTokenIsIdentifierOrStartOfDestructuring); + } + + function parseStatement(): Statement { + switch (token()) { + case SyntaxKind.SemicolonToken: + return parseEmptyStatement(); + case SyntaxKind.OpenBraceToken: + return parseBlock(/*ignoreMissingOpenBrace*/ false); + case SyntaxKind.VarKeyword: + return parseVariableStatement(createNodeWithJSDoc(SyntaxKind.VariableDeclaration)); + case SyntaxKind.LetKeyword: + if (isLetDeclaration()) { + return parseVariableStatement(createNodeWithJSDoc(SyntaxKind.VariableDeclaration)); + } + break; + case SyntaxKind.FunctionKeyword: + return parseFunctionDeclaration(createNodeWithJSDoc(SyntaxKind.FunctionDeclaration)); + case SyntaxKind.ClassKeyword: + return parseClassDeclaration(createNodeWithJSDoc(SyntaxKind.ClassDeclaration)); + case SyntaxKind.IfKeyword: + return parseIfStatement(); + case SyntaxKind.DoKeyword: + return parseDoStatement(); + case SyntaxKind.WhileKeyword: + return parseWhileStatement(); + case SyntaxKind.ForKeyword: + return parseForOrForInOrForOfStatement(); + case SyntaxKind.ContinueKeyword: + return parseBreakOrContinueStatement(SyntaxKind.ContinueStatement); + case SyntaxKind.BreakKeyword: + return parseBreakOrContinueStatement(SyntaxKind.BreakStatement); + case SyntaxKind.ReturnKeyword: + return parseReturnStatement(); + case SyntaxKind.WithKeyword: + return parseWithStatement(); + case SyntaxKind.SwitchKeyword: + return parseSwitchStatement(); + case SyntaxKind.ThrowKeyword: + return parseThrowStatement(); + case SyntaxKind.TryKeyword: + // Include 'catch' and 'finally' for error recovery. + case SyntaxKind.CatchKeyword: + case SyntaxKind.FinallyKeyword: + return parseTryStatement(); + case SyntaxKind.DebuggerKeyword: + return parseDebuggerStatement(); + case SyntaxKind.AtToken: + return parseDeclaration(); + case SyntaxKind.AsyncKeyword: + case SyntaxKind.InterfaceKeyword: + case SyntaxKind.TypeKeyword: + case SyntaxKind.ModuleKeyword: + case SyntaxKind.NamespaceKeyword: + case SyntaxKind.DeclareKeyword: + case SyntaxKind.ConstKeyword: + case SyntaxKind.EnumKeyword: + case SyntaxKind.ExportKeyword: + case SyntaxKind.ImportKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.PublicKeyword: + case SyntaxKind.AbstractKeyword: + case SyntaxKind.StaticKeyword: + case SyntaxKind.ReadonlyKeyword: + case SyntaxKind.GlobalKeyword: + if (isStartOfDeclaration()) { + return parseDeclaration(); + } + break; + } + return parseExpressionOrLabeledStatement(); + } + + function isDeclareModifier(modifier: Modifier) { + return modifier.kind === SyntaxKind.DeclareKeyword; + } + + function parseDeclaration(): Statement { + const node = createNodeWithJSDoc(SyntaxKind.Unknown); + node.decorators = parseDecorators(); + node.modifiers = parseModifiers(); + if (some(node.modifiers, isDeclareModifier)) { + for (const m of node.modifiers!) { + m.flags |= NodeFlags.Ambient; + } + return doInsideOfContext(NodeFlags.Ambient, () => parseDeclarationWorker(node)); + } + else { + return parseDeclarationWorker(node); + } + } + + function parseDeclarationWorker(node: Statement): Statement { + switch (token()) { + case SyntaxKind.VarKeyword: + case SyntaxKind.LetKeyword: + case SyntaxKind.ConstKeyword: + return parseVariableStatement(node); + case SyntaxKind.FunctionKeyword: + return parseFunctionDeclaration(node); + case SyntaxKind.ClassKeyword: + return parseClassDeclaration(node); + case SyntaxKind.InterfaceKeyword: + return parseInterfaceDeclaration(node); + case SyntaxKind.TypeKeyword: + return parseTypeAliasDeclaration(node); + case SyntaxKind.EnumKeyword: + return parseEnumDeclaration(node); + case SyntaxKind.GlobalKeyword: + case SyntaxKind.ModuleKeyword: + case SyntaxKind.NamespaceKeyword: + return parseModuleDeclaration(node); + case SyntaxKind.ImportKeyword: + return parseImportDeclarationOrImportEqualsDeclaration(node); + case SyntaxKind.ExportKeyword: + nextToken(); + switch (token()) { + case SyntaxKind.DefaultKeyword: + case SyntaxKind.EqualsToken: + return parseExportAssignment(node); + case SyntaxKind.AsKeyword: + return parseNamespaceExportDeclaration(node); + default: + return parseExportDeclaration(node); + } + default: + if (node.decorators || node.modifiers) { + // We reached this point because we encountered decorators and/or modifiers and assumed a declaration + // would follow. For recovery and error reporting purposes, return an incomplete declaration. + const missing = createMissingNode(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); + missing.pos = node.pos; + missing.decorators = node.decorators; + missing.modifiers = node.modifiers; + return finishNode(missing); + } + return undefined!; // TODO: GH#18217 + } + } + + function nextTokenIsIdentifierOrStringLiteralOnSameLine() { + nextToken(); + return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token() === SyntaxKind.StringLiteral); + } + + function parseFunctionBlockOrSemicolon(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block | undefined { + if (token() !== SyntaxKind.OpenBraceToken && canParseSemicolon()) { + parseSemicolon(); + return; + } + + return parseFunctionBlock(flags, diagnosticMessage); + } + + // DECLARATIONS + + function parseArrayBindingElement(): ArrayBindingElement { + if (token() === SyntaxKind.CommaToken) { + return createNode(SyntaxKind.OmittedExpression); + } + const node = createNode(SyntaxKind.BindingElement); + node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); + node.name = parseIdentifierOrPattern(); + node.initializer = parseInitializer(); + return finishNode(node); + } + + function parseObjectBindingElement(): BindingElement { + const node = createNode(SyntaxKind.BindingElement); + node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); + const tokenIsIdentifier = isIdentifier(); + const propertyName = parsePropertyName(); + if (tokenIsIdentifier && token() !== SyntaxKind.ColonToken) { + node.name = propertyName; + } + else { + parseExpected(SyntaxKind.ColonToken); + node.propertyName = propertyName; + node.name = parseIdentifierOrPattern(); + } + node.initializer = parseInitializer(); + return finishNode(node); + } + + function parseObjectBindingPattern(): ObjectBindingPattern { + const node = createNode(SyntaxKind.ObjectBindingPattern); + parseExpected(SyntaxKind.OpenBraceToken); + node.elements = parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement); + parseExpected(SyntaxKind.CloseBraceToken); + return finishNode(node); + } + + function parseArrayBindingPattern(): ArrayBindingPattern { + const node = createNode(SyntaxKind.ArrayBindingPattern); + parseExpected(SyntaxKind.OpenBracketToken); + node.elements = parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement); + parseExpected(SyntaxKind.CloseBracketToken); + return finishNode(node); + } + + function isIdentifierOrPattern() { + return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken || isIdentifier(); + } + + function parseIdentifierOrPattern(): Identifier | BindingPattern { + if (token() === SyntaxKind.OpenBracketToken) { + return parseArrayBindingPattern(); + } + if (token() === SyntaxKind.OpenBraceToken) { + return parseObjectBindingPattern(); + } + return parseIdentifier(); + } + + function parseVariableDeclarationAllowExclamation() { + return parseVariableDeclaration(/*allowExclamation*/ true); + } + + function parseVariableDeclaration(allowExclamation?: boolean): VariableDeclaration { + const node = createNode(SyntaxKind.VariableDeclaration); + node.name = parseIdentifierOrPattern(); + if (allowExclamation && node.name.kind === SyntaxKind.Identifier && + token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { + node.exclamationToken = parseTokenNode>(); + } + node.type = parseTypeAnnotation(); + if (!isInOrOfKeyword(token())) { + node.initializer = parseInitializer(); + } + return finishNode(node); + } + + function parseVariableDeclarationList(inForStatementInitializer: boolean): VariableDeclarationList { + const node = createNode(SyntaxKind.VariableDeclarationList); + + switch (token()) { + case SyntaxKind.VarKeyword: + break; + case SyntaxKind.LetKeyword: + node.flags |= NodeFlags.Let; + break; + case SyntaxKind.ConstKeyword: + node.flags |= NodeFlags.Const; + break; + default: + Debug.fail(); + } + + nextToken(); + + // The user may have written the following: + // + // for (let of X) { } + // + // In this case, we want to parse an empty declaration list, and then parse 'of' + // as a keyword. The reason this is not automatic is that 'of' is a valid identifier. + // So we need to look ahead to determine if 'of' should be treated as a keyword in + // this context. + // The checker will then give an error that there is an empty declaration list. + if (token() === SyntaxKind.OfKeyword && lookAhead(canFollowContextualOfKeyword)) { + node.declarations = createMissingList(); + } + else { + const savedDisallowIn = inDisallowInContext(); + setDisallowInContext(inForStatementInitializer); + + node.declarations = parseDelimitedList(ParsingContext.VariableDeclarations, + inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation); + + setDisallowInContext(savedDisallowIn); + } + + return finishNode(node); + } + + function canFollowContextualOfKeyword(): boolean { + return nextTokenIsIdentifier() && nextToken() === SyntaxKind.CloseParenToken; + } + + function parseVariableStatement(node: VariableStatement): VariableStatement { + node.kind = SyntaxKind.VariableStatement; + node.declarationList = parseVariableDeclarationList(/*inForStatementInitializer*/ false); + parseSemicolon(); + return finishNode(node); + } + + function parseFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration { + node.kind = SyntaxKind.FunctionDeclaration; + parseExpected(SyntaxKind.FunctionKeyword); + node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); + node.name = hasModifier(node, ModifierFlags.Default) ? parseOptionalIdentifier() : parseIdentifier(); + const isGenerator = node.asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; + const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None; + fillSignature(SyntaxKind.ColonToken, isGenerator | isAsync, node); + node.body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, Diagnostics.or_expected); + return finishNode(node); + } + + function parseConstructorDeclaration(node: ConstructorDeclaration): ConstructorDeclaration { + node.kind = SyntaxKind.Constructor; + parseExpected(SyntaxKind.ConstructorKeyword); + fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node); + node.body = parseFunctionBlockOrSemicolon(SignatureFlags.None, Diagnostics.or_expected); + return finishNode(node); + } + + function parseMethodDeclaration(node: MethodDeclaration, asteriskToken: AsteriskToken, diagnosticMessage?: DiagnosticMessage): MethodDeclaration { + node.kind = SyntaxKind.MethodDeclaration; + node.asteriskToken = asteriskToken; + const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; + const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None; + fillSignature(SyntaxKind.ColonToken, isGenerator | isAsync, node); + node.body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, diagnosticMessage); + return finishNode(node); + } + + function parsePropertyDeclaration(node: PropertyDeclaration): PropertyDeclaration { + node.kind = SyntaxKind.PropertyDeclaration; + if (!node.questionToken && token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { + node.exclamationToken = parseTokenNode>(); + } + node.type = parseTypeAnnotation(); + + // For instance properties specifically, since they are evaluated inside the constructor, + // we do *not * want to parse yield expressions, so we specifically turn the yield context + // off. The grammar would look something like this: + // + // MemberVariableDeclaration[Yield]: + // AccessibilityModifier_opt PropertyName TypeAnnotation_opt Initializer_opt[In]; + // AccessibilityModifier_opt static_opt PropertyName TypeAnnotation_opt Initializer_opt[In, ?Yield]; + // + // The checker may still error in the static case to explicitly disallow the yield expression. + node.initializer = hasModifier(node, ModifierFlags.Static) + ? allowInAnd(parseInitializer) + : doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.DisallowInContext, parseInitializer); + + parseSemicolon(); + return finishNode(node); + } + + function parsePropertyOrMethodDeclaration(node: PropertyDeclaration | MethodDeclaration): PropertyDeclaration | MethodDeclaration { + const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); + node.name = parsePropertyName(); + // Note: this is not legal as per the grammar. But we allow it in the parser and + // report an error in the grammar checker. + node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken); + if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { + return parseMethodDeclaration(node, asteriskToken, Diagnostics.or_expected); + } + return parsePropertyDeclaration(node); + } + + function parseAccessorDeclaration(node: AccessorDeclaration, kind: AccessorDeclaration["kind"]): AccessorDeclaration { + node.kind = kind; + node.name = parsePropertyName(); + fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node); + node.body = parseFunctionBlockOrSemicolon(SignatureFlags.None); + return finishNode(node); + } + + function isClassMemberStart(): boolean { + let idToken: SyntaxKind | undefined; + + if (token() === SyntaxKind.AtToken) { + return true; + } + + // Eat up all modifiers, but hold on to the last one in case it is actually an identifier. + while (isModifierKind(token())) { + idToken = token(); + // If the idToken is a class modifier (protected, private, public, and static), it is + // certain that we are starting to parse class member. This allows better error recovery + // Example: + // public foo() ... // true + // public @dec blah ... // true; we will then report an error later + // export public ... // true; we will then report an error later + if (isClassMemberModifier(idToken)) { + return true; + } + + nextToken(); + } + + if (token() === SyntaxKind.AsteriskToken) { + return true; + } + + // Try to get the first property-like token following all modifiers. + // This can either be an identifier or the 'get' or 'set' keywords. + if (isLiteralPropertyName()) { + idToken = token(); + nextToken(); + } + + // Index signatures and computed properties are class members; we can parse. + if (token() === SyntaxKind.OpenBracketToken) { + return true; + } + + // If we were able to get any potential identifier... + if (idToken !== undefined) { + // If we have a non-keyword identifier, or if we have an accessor, then it's safe to parse. + if (!isKeyword(idToken) || idToken === SyntaxKind.SetKeyword || idToken === SyntaxKind.GetKeyword) { + return true; + } + + // If it *is* a keyword, but not an accessor, check a little farther along + // to see if it should actually be parsed as a class member. + switch (token()) { + case SyntaxKind.OpenParenToken: // Method declaration + case SyntaxKind.LessThanToken: // Generic Method declaration + case SyntaxKind.ExclamationToken: // Non-null assertion on property name + case SyntaxKind.ColonToken: // Type Annotation for declaration + case SyntaxKind.EqualsToken: // Initializer for declaration + case SyntaxKind.QuestionToken: // Not valid, but permitted so that it gets caught later on. + return true; + default: + // Covers + // - Semicolons (declaration termination) + // - Closing braces (end-of-class, must be declaration) + // - End-of-files (not valid, but permitted so that it gets caught later on) + // - Line-breaks (enabling *automatic semicolon insertion*) + return canParseSemicolon(); + } + } + + return false; + } + + function parseDecorators(): NodeArray | undefined { + let list: Decorator[] | undefined; + const listPos = getNodePos(); + while (true) { + const decoratorStart = getNodePos(); + if (!parseOptional(SyntaxKind.AtToken)) { + break; + } + const decorator = createNode(SyntaxKind.Decorator, decoratorStart); + decorator.expression = doInDecoratorContext(parseLeftHandSideExpressionOrHigher); + finishNode(decorator); + (list || (list = [])).push(decorator); + } + return list && createNodeArray(list, listPos); + } + + /* + * There are situations in which a modifier like 'const' will appear unexpectedly, such as on a class member. + * In those situations, if we are entirely sure that 'const' is not valid on its own (such as when ASI takes effect + * and turns it into a standalone declaration), then it is better to parse it and report an error later. + * + * In such situations, 'permitInvalidConstAsModifier' should be set to true. + */ + function parseModifiers(permitInvalidConstAsModifier?: boolean): NodeArray | undefined { + let list: Modifier[] | undefined; + const listPos = getNodePos(); + while (true) { + const modifierStart = scanner.getStartPos(); + const modifierKind = token(); + + if (token() === SyntaxKind.ConstKeyword && permitInvalidConstAsModifier) { + // We need to ensure that any subsequent modifiers appear on the same line + // so that when 'const' is a standalone declaration, we don't issue an error. + if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) { + break; + } + } + else { + if (!parseAnyContextualModifier()) { + break; + } + } + + const modifier = finishNode(createNode(modifierKind, modifierStart)); + (list || (list = [])).push(modifier); + } + return list && createNodeArray(list, listPos); + } + + function parseModifiersForArrowFunction(): NodeArray | undefined { + let modifiers: NodeArray | undefined; + if (token() === SyntaxKind.AsyncKeyword) { + const modifierStart = scanner.getStartPos(); + const modifierKind = token(); + nextToken(); + const modifier = finishNode(createNode(modifierKind, modifierStart)); + modifiers = createNodeArray([modifier], modifierStart); + } + return modifiers; + } + + function parseClassElement(): ClassElement { + if (token() === SyntaxKind.SemicolonToken) { + const result = createNode(SyntaxKind.SemicolonClassElement); + nextToken(); + return finishNode(result); + } + + const node = createNodeWithJSDoc(SyntaxKind.Unknown); + node.decorators = parseDecorators(); + node.modifiers = parseModifiers(/*permitInvalidConstAsModifier*/ true); + + if (parseContextualModifier(SyntaxKind.GetKeyword)) { + return parseAccessorDeclaration(node, SyntaxKind.GetAccessor); + } + + if (parseContextualModifier(SyntaxKind.SetKeyword)) { + return parseAccessorDeclaration(node, SyntaxKind.SetAccessor); + } + + if (token() === SyntaxKind.ConstructorKeyword) { + return parseConstructorDeclaration(node); + } + + if (isIndexSignature()) { + return parseIndexSignatureDeclaration(node); + } + + // It is very important that we check this *after* checking indexers because + // the [ token can start an index signature or a computed property name + if (tokenIsIdentifierOrKeyword(token()) || + token() === SyntaxKind.StringLiteral || + token() === SyntaxKind.NumericLiteral || + token() === SyntaxKind.AsteriskToken || + token() === SyntaxKind.OpenBracketToken) { + + return parsePropertyOrMethodDeclaration(node); + } + + if (node.decorators || node.modifiers) { + // treat this as a property declaration with a missing name. + node.name = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); + return parsePropertyDeclaration(node); + } + + // 'isClassMemberStart' should have hinted not to attempt parsing. + return Debug.fail("Should not have attempted to parse class member declaration."); + } + + function parseClassExpression(): ClassExpression { + return parseClassDeclarationOrExpression(createNodeWithJSDoc(SyntaxKind.Unknown), SyntaxKind.ClassExpression); + } + + function parseClassDeclaration(node: ClassLikeDeclaration): ClassDeclaration { + return parseClassDeclarationOrExpression(node, SyntaxKind.ClassDeclaration); + } + + function parseClassDeclarationOrExpression(node: ClassLikeDeclaration, kind: ClassLikeDeclaration["kind"]): ClassLikeDeclaration { + node.kind = kind; + parseExpected(SyntaxKind.ClassKeyword); + node.name = parseNameOfClassDeclarationOrExpression(); + node.typeParameters = parseTypeParameters(); + node.heritageClauses = parseHeritageClauses(); + + if (parseExpected(SyntaxKind.OpenBraceToken)) { + // ClassTail[Yield,Await] : (Modified) See 14.5 + // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt } + node.members = parseClassMembers(); + parseExpected(SyntaxKind.CloseBraceToken); + } + else { + node.members = createMissingList(); + } + + return finishNode(node); + } + + function parseNameOfClassDeclarationOrExpression(): Identifier | undefined { + // implements is a future reserved word so + // 'class implements' might mean either + // - class expression with omitted name, 'implements' starts heritage clause + // - class with name 'implements' + // 'isImplementsClause' helps to disambiguate between these two cases + return isIdentifier() && !isImplementsClause() + ? parseIdentifier() + : undefined; + } + + function isImplementsClause() { + return token() === SyntaxKind.ImplementsKeyword && lookAhead(nextTokenIsIdentifierOrKeyword); + } + + function parseHeritageClauses(): NodeArray | undefined { + // ClassTail[Yield,Await] : (Modified) See 14.5 + // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt } + + if (isHeritageClause()) { + return parseList(ParsingContext.HeritageClauses, parseHeritageClause); + } + + return undefined; + } + + function parseHeritageClause(): HeritageClause { + const tok = token(); + Debug.assert(tok === SyntaxKind.ExtendsKeyword || tok === SyntaxKind.ImplementsKeyword); // isListElement() should ensure this. + const node = createNode(SyntaxKind.HeritageClause); + node.token = tok as SyntaxKind.ExtendsKeyword | SyntaxKind.ImplementsKeyword; + nextToken(); + node.types = parseDelimitedList(ParsingContext.HeritageClauseElement, parseExpressionWithTypeArguments); + return finishNode(node); + } + + function parseExpressionWithTypeArguments(): ExpressionWithTypeArguments { + const node = createNode(SyntaxKind.ExpressionWithTypeArguments); + node.expression = parseLeftHandSideExpressionOrHigher(); + node.typeArguments = tryParseTypeArguments(); + return finishNode(node); + } + + function tryParseTypeArguments(): NodeArray | undefined { + return token() === SyntaxKind.LessThanToken + ? parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken) + : undefined; + } + + function isHeritageClause(): boolean { + return token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; + } + + function parseClassMembers(): NodeArray { + return parseList(ParsingContext.ClassMembers, parseClassElement); + } + + function parseInterfaceDeclaration(node: InterfaceDeclaration): InterfaceDeclaration { + node.kind = SyntaxKind.InterfaceDeclaration; + parseExpected(SyntaxKind.InterfaceKeyword); + node.name = parseIdentifier(); + node.typeParameters = parseTypeParameters(); + node.heritageClauses = parseHeritageClauses(); + node.members = parseObjectTypeMembers(); + return finishNode(node); + } + + function parseTypeAliasDeclaration(node: TypeAliasDeclaration): TypeAliasDeclaration { + node.kind = SyntaxKind.TypeAliasDeclaration; + parseExpected(SyntaxKind.TypeKeyword); + node.name = parseIdentifier(); + node.typeParameters = parseTypeParameters(); + parseExpected(SyntaxKind.EqualsToken); + node.type = parseType(); + parseSemicolon(); + return finishNode(node); + } + + // In an ambient declaration, the grammar only allows integer literals as initializers. + // In a non-ambient declaration, the grammar allows uninitialized members only in a + // ConstantEnumMemberSection, which starts at the beginning of an enum declaration + // or any time an integer literal initializer is encountered. + function parseEnumMember(): EnumMember { + const node = createNodeWithJSDoc(SyntaxKind.EnumMember); + node.name = parsePropertyName(); + node.initializer = allowInAnd(parseInitializer); + return finishNode(node); + } + + function parseEnumDeclaration(node: EnumDeclaration): EnumDeclaration { + node.kind = SyntaxKind.EnumDeclaration; + parseExpected(SyntaxKind.EnumKeyword); + node.name = parseIdentifier(); + if (parseExpected(SyntaxKind.OpenBraceToken)) { + node.members = parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember); + parseExpected(SyntaxKind.CloseBraceToken); + } + else { + node.members = createMissingList(); + } + return finishNode(node); + } + + function parseModuleBlock(): ModuleBlock { + const node = createNode(SyntaxKind.ModuleBlock); + if (parseExpected(SyntaxKind.OpenBraceToken)) { + node.statements = parseList(ParsingContext.BlockStatements, parseStatement); + parseExpected(SyntaxKind.CloseBraceToken); + } + else { + node.statements = createMissingList(); + } + return finishNode(node); + } + + function parseModuleOrNamespaceDeclaration(node: ModuleDeclaration, flags: NodeFlags): ModuleDeclaration { + node.kind = SyntaxKind.ModuleDeclaration; + // If we are parsing a dotted namespace name, we want to + // propagate the 'Namespace' flag across the names if set. + const namespaceFlag = flags & NodeFlags.Namespace; + node.flags |= flags; + node.name = parseIdentifier(); + node.body = parseOptional(SyntaxKind.DotToken) + ? parseModuleOrNamespaceDeclaration(createNode(SyntaxKind.Unknown), NodeFlags.NestedNamespace | namespaceFlag) + : parseModuleBlock(); + return finishNode(node); + } + + function parseAmbientExternalModuleDeclaration(node: ModuleDeclaration): ModuleDeclaration { + node.kind = SyntaxKind.ModuleDeclaration; + if (token() === SyntaxKind.GlobalKeyword) { + // parse 'global' as name of global scope augmentation + node.name = parseIdentifier(); + node.flags |= NodeFlags.GlobalAugmentation; + } + else { + node.name = parseLiteralNode(); + node.name.text = internIdentifier(node.name.text); + } + if (token() === SyntaxKind.OpenBraceToken) { + node.body = parseModuleBlock(); + } + else { + parseSemicolon(); + } + return finishNode(node); + } + + function parseModuleDeclaration(node: ModuleDeclaration): ModuleDeclaration { + let flags: NodeFlags = 0; + if (token() === SyntaxKind.GlobalKeyword) { + // global augmentation + return parseAmbientExternalModuleDeclaration(node); + } + else if (parseOptional(SyntaxKind.NamespaceKeyword)) { + flags |= NodeFlags.Namespace; + } + else { + parseExpected(SyntaxKind.ModuleKeyword); + if (token() === SyntaxKind.StringLiteral) { + return parseAmbientExternalModuleDeclaration(node); + } + } + return parseModuleOrNamespaceDeclaration(node, flags); + } + + function isExternalModuleReference() { + return token() === SyntaxKind.RequireKeyword && + lookAhead(nextTokenIsOpenParen); + } + + function nextTokenIsOpenParen() { + return nextToken() === SyntaxKind.OpenParenToken; + } + + function nextTokenIsSlash() { + return nextToken() === SyntaxKind.SlashToken; + } + + function parseNamespaceExportDeclaration(node: NamespaceExportDeclaration): NamespaceExportDeclaration { + node.kind = SyntaxKind.NamespaceExportDeclaration; + parseExpected(SyntaxKind.AsKeyword); + parseExpected(SyntaxKind.NamespaceKeyword); + node.name = parseIdentifier(); + parseSemicolon(); + return finishNode(node); + } + + function parseImportDeclarationOrImportEqualsDeclaration(node: ImportEqualsDeclaration | ImportDeclaration): ImportEqualsDeclaration | ImportDeclaration { + parseExpected(SyntaxKind.ImportKeyword); + const afterImportPos = scanner.getStartPos(); + + let identifier: Identifier | undefined; + if (isIdentifier()) { + identifier = parseIdentifier(); + if (token() !== SyntaxKind.CommaToken && token() !== SyntaxKind.FromKeyword) { + return parseImportEqualsDeclaration(node, identifier); + } + } + + // Import statement + node.kind = SyntaxKind.ImportDeclaration; + // ImportDeclaration: + // import ImportClause from ModuleSpecifier ; + // import ModuleSpecifier; + if (identifier || // import id + token() === SyntaxKind.AsteriskToken || // import * + token() === SyntaxKind.OpenBraceToken) { // import { + (node).importClause = parseImportClause(identifier, afterImportPos); + parseExpected(SyntaxKind.FromKeyword); + } + + (node).moduleSpecifier = parseModuleSpecifier(); + parseSemicolon(); + return finishNode(node); + } + + function parseImportEqualsDeclaration(node: ImportEqualsDeclaration, identifier: Identifier): ImportEqualsDeclaration { + node.kind = SyntaxKind.ImportEqualsDeclaration; + node.name = identifier; + parseExpected(SyntaxKind.EqualsToken); + node.moduleReference = parseModuleReference(); + parseSemicolon(); + return finishNode(node); + } + + function parseImportClause(identifier: Identifier | undefined, fullStart: number) { + // ImportClause: + // ImportedDefaultBinding + // NameSpaceImport + // NamedImports + // ImportedDefaultBinding, NameSpaceImport + // ImportedDefaultBinding, NamedImports + + const importClause = createNode(SyntaxKind.ImportClause, fullStart); + if (identifier) { + // ImportedDefaultBinding: + // ImportedBinding + importClause.name = identifier; + } + + // If there was no default import or if there is comma token after default import + // parse namespace or named imports + if (!importClause.name || + parseOptional(SyntaxKind.CommaToken)) { + importClause.namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImportsOrExports(SyntaxKind.NamedImports); + } + + return finishNode(importClause); + } + + function parseModuleReference() { + return isExternalModuleReference() + ? parseExternalModuleReference() + : parseEntityName(/*allowReservedWords*/ false); + } + + function parseExternalModuleReference() { + const node = createNode(SyntaxKind.ExternalModuleReference); + parseExpected(SyntaxKind.RequireKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.expression = parseModuleSpecifier(); + parseExpected(SyntaxKind.CloseParenToken); + return finishNode(node); + } + + function parseModuleSpecifier(): Expression { + if (token() === SyntaxKind.StringLiteral) { + const result = parseLiteralNode(); + result.text = internIdentifier(result.text); + return result; + } + else { + // We allow arbitrary expressions here, even though the grammar only allows string + // literals. We check to ensure that it is only a string literal later in the grammar + // check pass. + return parseExpression(); + } + } + + function parseNamespaceImport(): NamespaceImport { + // NameSpaceImport: + // * as ImportedBinding + const namespaceImport = createNode(SyntaxKind.NamespaceImport); + parseExpected(SyntaxKind.AsteriskToken); + parseExpected(SyntaxKind.AsKeyword); + namespaceImport.name = parseIdentifier(); + return finishNode(namespaceImport); + } + + function parseNamedImportsOrExports(kind: SyntaxKind.NamedImports): NamedImports; + function parseNamedImportsOrExports(kind: SyntaxKind.NamedExports): NamedExports; + function parseNamedImportsOrExports(kind: SyntaxKind): NamedImportsOrExports { + const node = createNode(kind); + + // NamedImports: + // { } + // { ImportsList } + // { ImportsList, } + + // ImportsList: + // ImportSpecifier + // ImportsList, ImportSpecifier + node.elements = | NodeArray>parseBracketedList(ParsingContext.ImportOrExportSpecifiers, + kind === SyntaxKind.NamedImports ? parseImportSpecifier : parseExportSpecifier, + SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken); + return finishNode(node); + } + + function parseExportSpecifier() { + return parseImportOrExportSpecifier(SyntaxKind.ExportSpecifier); + } + + function parseImportSpecifier() { + return parseImportOrExportSpecifier(SyntaxKind.ImportSpecifier); + } + + function parseImportOrExportSpecifier(kind: SyntaxKind): ImportOrExportSpecifier { + const node = createNode(kind); + // ImportSpecifier: + // BindingIdentifier + // IdentifierName as BindingIdentifier + // ExportSpecifier: + // IdentifierName + // IdentifierName as IdentifierName + let checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier(); + let checkIdentifierStart = scanner.getTokenPos(); + let checkIdentifierEnd = scanner.getTextPos(); + const identifierName = parseIdentifierName(); + if (token() === SyntaxKind.AsKeyword) { + node.propertyName = identifierName; + parseExpected(SyntaxKind.AsKeyword); + checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier(); + checkIdentifierStart = scanner.getTokenPos(); + checkIdentifierEnd = scanner.getTextPos(); + node.name = parseIdentifierName(); + } + else { + node.name = identifierName; + } + if (kind === SyntaxKind.ImportSpecifier && checkIdentifierIsKeyword) { + parseErrorAt(checkIdentifierStart, checkIdentifierEnd, Diagnostics.Identifier_expected); + } + return finishNode(node); + } + + function parseExportDeclaration(node: ExportDeclaration): ExportDeclaration { + node.kind = SyntaxKind.ExportDeclaration; + if (parseOptional(SyntaxKind.AsteriskToken)) { + parseExpected(SyntaxKind.FromKeyword); + node.moduleSpecifier = parseModuleSpecifier(); + } + else { + node.exportClause = parseNamedImportsOrExports(SyntaxKind.NamedExports); + // It is not uncommon to accidentally omit the 'from' keyword. Additionally, in editing scenarios, + // the 'from' keyword can be parsed as a named export when the export clause is unterminated (i.e. `export { from "moduleName";`) + // If we don't have a 'from' keyword, see if we have a string literal such that ASI won't take effect. + if (token() === SyntaxKind.FromKeyword || (token() === SyntaxKind.StringLiteral && !scanner.hasPrecedingLineBreak())) { + parseExpected(SyntaxKind.FromKeyword); + node.moduleSpecifier = parseModuleSpecifier(); + } + } + parseSemicolon(); + return finishNode(node); + } + + function parseExportAssignment(node: ExportAssignment): ExportAssignment { + node.kind = SyntaxKind.ExportAssignment; + if (parseOptional(SyntaxKind.EqualsToken)) { + node.isExportEquals = true; + } + else { + parseExpected(SyntaxKind.DefaultKeyword); + } + node.expression = parseAssignmentExpressionOrHigher(); + parseSemicolon(); + return finishNode(node); + } + + function setExternalModuleIndicator(sourceFile: SourceFile) { + // Try to use the first top-level import/export when available, then + // fall back to looking for an 'import.meta' somewhere in the tree if necessary. + sourceFile.externalModuleIndicator = + forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) || + getImportMetaIfNecessary(sourceFile); + } + + function isAnExternalModuleIndicatorNode(node: Node) { + return hasModifier(node, ModifierFlags.Export) + || node.kind === SyntaxKind.ImportEqualsDeclaration && (node).moduleReference.kind === SyntaxKind.ExternalModuleReference + || node.kind === SyntaxKind.ImportDeclaration + || node.kind === SyntaxKind.ExportAssignment + || node.kind === SyntaxKind.ExportDeclaration + ? node + : undefined; + } + + function getImportMetaIfNecessary(sourceFile: SourceFile) { + return sourceFile.flags & NodeFlags.PossiblyContainsImportMeta ? + walkTreeForExternalModuleIndicators(sourceFile) : + undefined; + } + + function walkTreeForExternalModuleIndicators(node: Node): Node | undefined { + return isImportMeta(node) ? node : forEachChild(node, walkTreeForExternalModuleIndicators); + } + + function isImportMeta(node: Node): boolean { + return isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword && node.name.escapedText === "meta"; + } + + const enum ParsingContext { + SourceElements, // Elements in source file + BlockStatements, // Statements in block + SwitchClauses, // Clauses in switch statement + SwitchClauseStatements, // Statements in switch clause + TypeMembers, // Members in interface or type literal + ClassMembers, // Members in class declaration + EnumMembers, // Members in enum declaration + HeritageClauseElement, // Elements in a heritage clause + VariableDeclarations, // Variable declarations in variable statement + ObjectBindingElements, // Binding elements in object binding list + ArrayBindingElements, // Binding elements in array binding list + ArgumentExpressions, // Expressions in argument list + ObjectLiteralMembers, // Members in object literal + JsxAttributes, // Attributes in jsx element + JsxChildren, // Things between opening and closing JSX tags + ArrayLiteralMembers, // Members in array literal + Parameters, // Parameters in parameter list + JSDocParameters, // JSDoc parameters in parameter list of JSDoc function type + RestProperties, // Property names in a rest type list + TypeParameters, // Type parameters in type parameter list + TypeArguments, // Type arguments in type argument list + TupleElementTypes, // Element types in tuple element type list + HeritageClauses, // Heritage clauses for a class or interface declaration. + ImportOrExportSpecifiers, // Named import clause's import specifier list + Count // Number of parsing contexts + } + + const enum Tristate { + False, + True, + Unknown + } + + export namespace JSDocParser { + export function parseJSDocTypeExpressionForTests(content: string, start: number | undefined, length: number | undefined): { jsDocTypeExpression: JSDocTypeExpression, diagnostics: Diagnostic[] } | undefined { + initializeState(content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); + sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS, /*isDeclarationFile*/ false); + scanner.setText(content, start, length); + currentToken = scanner.scan(); + const jsDocTypeExpression = parseJSDocTypeExpression(); + const diagnostics = parseDiagnostics; + clearState(); + + return jsDocTypeExpression ? { jsDocTypeExpression, diagnostics } : undefined; + } + + // Parses out a JSDoc type expression. + export function parseJSDocTypeExpression(mayOmitBraces?: boolean): JSDocTypeExpression { + const result = createNode(SyntaxKind.JSDocTypeExpression, scanner.getTokenPos()); + + const hasBrace = (mayOmitBraces ? parseOptional : parseExpected)(SyntaxKind.OpenBraceToken); + result.type = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType); + if (!mayOmitBraces || hasBrace) { + parseExpected(SyntaxKind.CloseBraceToken); + } + + fixupParentReferences(result); + return finishNode(result); + } + + export function parseIsolatedJSDocComment(content: string, start: number | undefined, length: number | undefined): { jsDoc: JSDoc, diagnostics: Diagnostic[] } | undefined { + initializeState(content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); + sourceFile = { languageVariant: LanguageVariant.Standard, text: content }; // tslint:disable-line no-object-literal-type-assertion + const jsDoc = parseJSDocCommentWorker(start, length); + const diagnostics = parseDiagnostics; + clearState(); + + return jsDoc ? { jsDoc, diagnostics } : undefined; + } + + export function parseJSDocComment(parent: HasJSDoc, start: number, length: number): JSDoc | undefined { + const saveToken = currentToken; + const saveParseDiagnosticsLength = parseDiagnostics.length; + const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; + + const comment = parseJSDocCommentWorker(start, length); + if (comment) { + comment.parent = parent; + } + + if (contextFlags & NodeFlags.JavaScriptFile) { + if (!sourceFile.jsDocDiagnostics) { + sourceFile.jsDocDiagnostics = []; + } + sourceFile.jsDocDiagnostics.push(...parseDiagnostics); + } + currentToken = saveToken; + parseDiagnostics.length = saveParseDiagnosticsLength; + parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode; + + return comment; + } + + const enum JSDocState { + BeginningOfLine, + SawAsterisk, + SavingComments, + } + + const enum PropertyLikeParse { + Property = 1 << 0, + Parameter = 1 << 1, + CallbackParameter = 1 << 2, + } + + export function parseJSDocCommentWorker(start = 0, length: number | undefined): JSDoc | undefined { + const content = sourceText; + const end = length === undefined ? content.length : start + length; + length = end - start; + + Debug.assert(start >= 0); + Debug.assert(start <= end); + Debug.assert(end <= content.length); + + // Check for /** (JSDoc opening part) + if (!isJSDocLikeText(content, start)) { + return undefined; + } + + let tags: JSDocTag[]; + let tagsPos: number; + let tagsEnd: number; + const comments: string[] = []; + + // + 3 for leading /**, - 5 in total for /** */ + return scanner.scanRange(start + 3, length - 5, () => { + // Initially we can parse out a tag. We also have seen a starting asterisk. + // This is so that /** * @type */ doesn't parse. + let state = JSDocState.SawAsterisk; + let margin: number | undefined; + // + 4 for leading '/** ' + let indent = start - Math.max(content.lastIndexOf("\n", start), 0) + 4; + function pushComment(text: string) { + if (!margin) { + margin = indent; + } + comments.push(text); + indent += text.length; + } + + nextJSDocToken(); + while (parseOptionalJsdoc(SyntaxKind.WhitespaceTrivia)); + if (parseOptionalJsdoc(SyntaxKind.NewLineTrivia)) { + state = JSDocState.BeginningOfLine; + indent = 0; + } + loop: while (true) { + switch (token()) { + case SyntaxKind.AtToken: + if (state === JSDocState.BeginningOfLine || state === JSDocState.SawAsterisk) { + removeTrailingWhitespace(comments); + addTag(parseTag(indent)); + // NOTE: According to usejsdoc.org, a tag goes to end of line, except the last tag. + // Real-world comments may break this rule, so "BeginningOfLine" will not be a real line beginning + // for malformed examples like `/** @param {string} x @returns {number} the length */` + state = JSDocState.BeginningOfLine; + margin = undefined; + indent++; + } + else { + pushComment(scanner.getTokenText()); + } + break; + case SyntaxKind.NewLineTrivia: + comments.push(scanner.getTokenText()); + state = JSDocState.BeginningOfLine; + indent = 0; + break; + case SyntaxKind.AsteriskToken: + const asterisk = scanner.getTokenText(); + if (state === JSDocState.SawAsterisk || state === JSDocState.SavingComments) { + // If we've already seen an asterisk, then we can no longer parse a tag on this line + state = JSDocState.SavingComments; + pushComment(asterisk); + } + else { + // Ignore the first asterisk on a line + state = JSDocState.SawAsterisk; + indent += asterisk.length; + } + break; + case SyntaxKind.Identifier: + // Anything else is doc comment text. We just save it. Because it + // wasn't a tag, we can no longer parse a tag on this line until we hit the next + // line break. + pushComment(scanner.getTokenText()); + state = JSDocState.SavingComments; + break; + case SyntaxKind.WhitespaceTrivia: + // only collect whitespace if we're already saving comments or have just crossed the comment indent margin + const whitespace = scanner.getTokenText(); + if (state === JSDocState.SavingComments) { + comments.push(whitespace); + } + else if (margin !== undefined && indent + whitespace.length > margin) { + comments.push(whitespace.slice(margin - indent - 1)); + } + indent += whitespace.length; + break; + case SyntaxKind.EndOfFileToken: + break loop; + default: + // anything other than whitespace or asterisk at the beginning of the line starts the comment text + state = JSDocState.SavingComments; + pushComment(scanner.getTokenText()); + break; + } + nextJSDocToken(); + } + removeLeadingNewlines(comments); + removeTrailingWhitespace(comments); + return createJSDocComment(); + }); + + function removeLeadingNewlines(comments: string[]) { + while (comments.length && (comments[0] === "\n" || comments[0] === "\r")) { + comments.shift(); + } + } + + function removeTrailingWhitespace(comments: string[]) { + while (comments.length && comments[comments.length - 1].trim() === "") { + comments.pop(); + } + } + + function createJSDocComment(): JSDoc { + const result = createNode(SyntaxKind.JSDocComment, start); + result.tags = tags && createNodeArray(tags, tagsPos, tagsEnd); + result.comment = comments.length ? comments.join("") : undefined; + return finishNode(result, end); + } + + function isNextNonwhitespaceTokenEndOfFile(): boolean { + // We must use infinite lookahead, as there could be any number of newlines :( + while (true) { + nextJSDocToken(); + if (token() === SyntaxKind.EndOfFileToken) { + return true; + } + if (!(token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia)) { + return false; + } + } + } + + function skipWhitespace(): void { + if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { + if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) { + return; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range + } + } + while (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { + nextJSDocToken(); + } + } + + function skipWhitespaceOrAsterisk(): void { + if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { + if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) { + return; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range + } + } + + let precedingLineBreak = scanner.hasPrecedingLineBreak(); + while ((precedingLineBreak && token() === SyntaxKind.AsteriskToken) || token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { + if (token() === SyntaxKind.NewLineTrivia) { + precedingLineBreak = true; + } + else if (token() === SyntaxKind.AsteriskToken) { + precedingLineBreak = false; + } + nextJSDocToken(); + } + } + + function parseTag(indent: number) { + Debug.assert(token() === SyntaxKind.AtToken); + const atToken = createNode(SyntaxKind.AtToken, scanner.getTokenPos()); + atToken.end = scanner.getTextPos(); + nextJSDocToken(); + + const tagName = parseJSDocIdentifierName(); + skipWhitespaceOrAsterisk(); + + let tag: JSDocTag | undefined; + switch (tagName.escapedText) { + case "augments": + case "extends": + tag = parseAugmentsTag(atToken, tagName); + break; + case "class": + case "constructor": + tag = parseClassTag(atToken, tagName); + break; + case "this": + tag = parseThisTag(atToken, tagName); + break; + case "enum": + tag = parseEnumTag(atToken, tagName); + break; + case "arg": + case "argument": + case "param": + return parseParameterOrPropertyTag(atToken, tagName, PropertyLikeParse.Parameter, indent); + case "return": + case "returns": + tag = parseReturnTag(atToken, tagName); + break; + case "template": + tag = parseTemplateTag(atToken, tagName); + break; + case "type": + tag = parseTypeTag(atToken, tagName); + break; + case "typedef": + tag = parseTypedefTag(atToken, tagName, indent); + break; + case "callback": + tag = parseCallbackTag(atToken, tagName, indent); + break; + default: + tag = parseUnknownTag(atToken, tagName); + break; + } + + if (!tag.comment) { + // some tags, like typedef and callback, have already parsed their comments earlier + tag.comment = parseTagComments(indent + tag.end - tag.pos); + } + return tag; + } + + function parseTagComments(indent: number): string | undefined { + const comments: string[] = []; + let state = JSDocState.BeginningOfLine; + let margin: number | undefined; + function pushComment(text: string) { + if (!margin) { + margin = indent; + } + comments.push(text); + indent += text.length; + } + let tok = token() as JsDocSyntaxKind; + loop: while (true) { + switch (tok) { + case SyntaxKind.NewLineTrivia: + if (state >= JSDocState.SawAsterisk) { + state = JSDocState.BeginningOfLine; + comments.push(scanner.getTokenText()); + } + indent = 0; + break; + case SyntaxKind.AtToken: + scanner.setTextPos(scanner.getTextPos() - 1); + // falls through + case SyntaxKind.EndOfFileToken: + // Done + break loop; + case SyntaxKind.WhitespaceTrivia: + if (state === JSDocState.SavingComments) { + pushComment(scanner.getTokenText()); + } + else { + const whitespace = scanner.getTokenText(); + // if the whitespace crosses the margin, take only the whitespace that passes the margin + if (margin !== undefined && indent + whitespace.length > margin) { + comments.push(whitespace.slice(margin - indent - 1)); + } + indent += whitespace.length; + } + break; + case SyntaxKind.OpenBraceToken: + state = JSDocState.SavingComments; + if (lookAhead(() => nextJSDocToken() === SyntaxKind.AtToken && tokenIsIdentifierOrKeyword(nextJSDocToken()) && scanner.getTokenText() === "link")) { + pushComment(scanner.getTokenText()); + nextJSDocToken(); + pushComment(scanner.getTokenText()); + nextJSDocToken(); + } + pushComment(scanner.getTokenText()); + break; + case SyntaxKind.AsteriskToken: + if (state === JSDocState.BeginningOfLine) { + // leading asterisks start recording on the *next* (non-whitespace) token + state = JSDocState.SawAsterisk; + indent += 1; + break; + } + // record the * as a comment + // falls through + default: + state = JSDocState.SavingComments; // leading identifiers start recording as well + pushComment(scanner.getTokenText()); + break; + } + tok = nextJSDocToken(); + } + + removeLeadingNewlines(comments); + removeTrailingWhitespace(comments); + return comments.length === 0 ? undefined : comments.join(""); + } + + function parseUnknownTag(atToken: AtToken, tagName: Identifier) { + const result = createNode(SyntaxKind.JSDocTag, atToken.pos); + result.atToken = atToken; + result.tagName = tagName; + return finishNode(result); + } + + function addTag(tag: JSDocTag | undefined): void { + if (!tag) { + return; + } + if (!tags) { + tags = [tag]; + tagsPos = tag.pos; + } + else { + tags.push(tag); + } + tagsEnd = tag.end; + } + + function tryParseTypeExpression(): JSDocTypeExpression | undefined { + skipWhitespaceOrAsterisk(); + return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined; + } + + function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } { + if (token() === SyntaxKind.NoSubstitutionTemplateLiteral) { + // a markdown-quoted name: `arg` is not legal jsdoc, but occurs in the wild + return { name: createIdentifier(/*isIdentifier*/ true), isBracketed: false }; + } + // Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar' + const isBracketed = parseOptional(SyntaxKind.OpenBracketToken); + const name = parseJSDocEntityName(); + if (isBracketed) { + skipWhitespace(); + + // May have an optional default, e.g. '[foo = 42]' + if (parseOptionalToken(SyntaxKind.EqualsToken)) { + parseExpression(); + } + + parseExpected(SyntaxKind.CloseBracketToken); + } + + return { name, isBracketed }; + } + + function isObjectOrObjectArrayTypeReference(node: TypeNode): boolean { + switch (node.kind) { + case SyntaxKind.ObjectKeyword: + return true; + case SyntaxKind.ArrayType: + return isObjectOrObjectArrayTypeReference((node as ArrayTypeNode).elementType); + default: + return isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && node.typeName.escapedText === "Object"; + } + } + + function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, target: PropertyLikeParse, indent: number | undefined): JSDocParameterTag | JSDocPropertyTag { + let typeExpression = tryParseTypeExpression(); + let isNameFirst = !typeExpression; + skipWhitespaceOrAsterisk(); + + const { name, isBracketed } = parseBracketNameInPropertyAndParamTag(); + skipWhitespace(); + + if (isNameFirst) { + typeExpression = tryParseTypeExpression(); + } + + const result = target === PropertyLikeParse.Property ? + createNode(SyntaxKind.JSDocPropertyTag, atToken.pos) : + createNode(SyntaxKind.JSDocParameterTag, atToken.pos); + let comment: string | undefined; + if (indent !== undefined) comment = parseTagComments(indent + scanner.getStartPos() - atToken.pos); + const nestedTypeLiteral = target !== PropertyLikeParse.CallbackParameter && parseNestedTypeLiteral(typeExpression, name, target); + if (nestedTypeLiteral) { + typeExpression = nestedTypeLiteral; + isNameFirst = true; + } + result.atToken = atToken; + result.tagName = tagName; + result.typeExpression = typeExpression; + result.name = name; + result.isNameFirst = isNameFirst; + result.isBracketed = isBracketed; + result.comment = comment; + return finishNode(result); + } + + function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse) { + if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) { + const typeLiteralExpression = createNode(SyntaxKind.JSDocTypeExpression, scanner.getTokenPos()); + let child: JSDocPropertyLikeTag | JSDocTypeTag | false; + let jsdocTypeLiteral: JSDocTypeLiteral; + const start = scanner.getStartPos(); + let children: JSDocPropertyLikeTag[] | undefined; + while (child = tryParse(() => parseChildParameterOrPropertyTag(target, name))) { + if (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) { + children = append(children, child); + } + } + if (children) { + jsdocTypeLiteral = createNode(SyntaxKind.JSDocTypeLiteral, start); + jsdocTypeLiteral.jsDocPropertyTags = children; + if (typeExpression.type.kind === SyntaxKind.ArrayType) { + jsdocTypeLiteral.isArrayType = true; + } + typeLiteralExpression.type = finishNode(jsdocTypeLiteral); + return finishNode(typeLiteralExpression); + } + } + } + + function parseReturnTag(atToken: AtToken, tagName: Identifier): JSDocReturnTag { + if (forEach(tags, t => t.kind === SyntaxKind.JSDocReturnTag)) { + parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText); + } + + const result = createNode(SyntaxKind.JSDocReturnTag, atToken.pos); + result.atToken = atToken; + result.tagName = tagName; + result.typeExpression = tryParseTypeExpression(); + return finishNode(result); + } + + function parseTypeTag(atToken: AtToken, tagName: Identifier): JSDocTypeTag { + if (forEach(tags, t => t.kind === SyntaxKind.JSDocTypeTag)) { + parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText); + } + + const result = createNode(SyntaxKind.JSDocTypeTag, atToken.pos); + result.atToken = atToken; + result.tagName = tagName; + result.typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); + return finishNode(result); + } + + function parseAugmentsTag(atToken: AtToken, tagName: Identifier): JSDocAugmentsTag { + const result = createNode(SyntaxKind.JSDocAugmentsTag, atToken.pos); + result.atToken = atToken; + result.tagName = tagName; + result.class = parseExpressionWithTypeArgumentsForAugments(); + return finishNode(result); + } + + function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression } { + const usedBrace = parseOptional(SyntaxKind.OpenBraceToken); + const node = createNode(SyntaxKind.ExpressionWithTypeArguments) as ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression }; + node.expression = parsePropertyAccessEntityNameExpression(); + node.typeArguments = tryParseTypeArguments(); + const res = finishNode(node); + if (usedBrace) { + parseExpected(SyntaxKind.CloseBraceToken); + } + return res; + } + + function parsePropertyAccessEntityNameExpression() { + let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName(); + while (parseOptional(SyntaxKind.DotToken)) { + const prop: PropertyAccessEntityNameExpression = createNode(SyntaxKind.PropertyAccessExpression, node.pos) as PropertyAccessEntityNameExpression; + prop.expression = node; + prop.name = parseJSDocIdentifierName(); + node = finishNode(prop); + } + return node; + } + + function parseClassTag(atToken: AtToken, tagName: Identifier): JSDocClassTag { + const tag = createNode(SyntaxKind.JSDocClassTag, atToken.pos); + tag.atToken = atToken; + tag.tagName = tagName; + return finishNode(tag); + } + + function parseThisTag(atToken: AtToken, tagName: Identifier): JSDocThisTag { + const tag = createNode(SyntaxKind.JSDocThisTag, atToken.pos); + tag.atToken = atToken; + tag.tagName = tagName; + tag.typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); + skipWhitespace(); + return finishNode(tag); + } + + function parseEnumTag(atToken: AtToken, tagName: Identifier): JSDocEnumTag { + const tag = createNode(SyntaxKind.JSDocEnumTag, atToken.pos); + tag.atToken = atToken; + tag.tagName = tagName; + tag.typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); + skipWhitespace(); + return finishNode(tag); + } + + function parseTypedefTag(atToken: AtToken, tagName: Identifier, indent: number): JSDocTypedefTag { + const typeExpression = tryParseTypeExpression(); + skipWhitespace(); + + const typedefTag = createNode(SyntaxKind.JSDocTypedefTag, atToken.pos); + typedefTag.atToken = atToken; + typedefTag.tagName = tagName; + typedefTag.fullName = parseJSDocTypeNameWithNamespace(); + typedefTag.name = getJSDocTypeAliasName(typedefTag.fullName); + skipWhitespace(); + typedefTag.comment = parseTagComments(indent); + + typedefTag.typeExpression = typeExpression; + let end: number | undefined; + if (!typeExpression || isObjectOrObjectArrayTypeReference(typeExpression.type)) { + let child: JSDocTypeTag | JSDocPropertyTag | false; + let jsdocTypeLiteral: JSDocTypeLiteral | undefined; + let childTypeTag: JSDocTypeTag | undefined; + const start = atToken.pos; + while (child = tryParse(() => parseChildPropertyTag())) { + if (!jsdocTypeLiteral) { + jsdocTypeLiteral = createNode(SyntaxKind.JSDocTypeLiteral, start); + } + if (child.kind === SyntaxKind.JSDocTypeTag) { + if (childTypeTag) { + break; + } + else { + childTypeTag = child; + } + } + else { + jsdocTypeLiteral.jsDocPropertyTags = append(jsdocTypeLiteral.jsDocPropertyTags as MutableNodeArray, child); + } + } + if (jsdocTypeLiteral) { + if (typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType) { + jsdocTypeLiteral.isArrayType = true; + } + typedefTag.typeExpression = childTypeTag && childTypeTag.typeExpression && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) ? + childTypeTag.typeExpression : + finishNode(jsdocTypeLiteral); + end = typedefTag.typeExpression.end; + } + } + + // Only include the characters between the name end and the next token if a comment was actually parsed out - otherwise it's just whitespace + return finishNode(typedefTag, end || typedefTag.comment !== undefined ? scanner.getStartPos() : (typedefTag.fullName || typedefTag.typeExpression || typedefTag.tagName).end); + } + + function parseJSDocTypeNameWithNamespace(nested?: boolean) { + const pos = scanner.getTokenPos(); + if (!tokenIsIdentifierOrKeyword(token())) { + return undefined; + } + const typeNameOrNamespaceName = parseJSDocIdentifierName(); + if (parseOptional(SyntaxKind.DotToken)) { + const jsDocNamespaceNode = createNode(SyntaxKind.ModuleDeclaration, pos); + if (nested) { + jsDocNamespaceNode.flags |= NodeFlags.NestedNamespace; + } + jsDocNamespaceNode.name = typeNameOrNamespaceName; + jsDocNamespaceNode.body = parseJSDocTypeNameWithNamespace(/*nested*/ true); + return finishNode(jsDocNamespaceNode); + } + + if (nested) { + typeNameOrNamespaceName.isInJSDocNamespace = true; + } + return typeNameOrNamespaceName; + } + + function parseCallbackTag(atToken: AtToken, tagName: Identifier, indent: number): JSDocCallbackTag { + const callbackTag = createNode(SyntaxKind.JSDocCallbackTag, atToken.pos) as JSDocCallbackTag; + callbackTag.atToken = atToken; + callbackTag.tagName = tagName; + callbackTag.fullName = parseJSDocTypeNameWithNamespace(); + callbackTag.name = getJSDocTypeAliasName(callbackTag.fullName); + skipWhitespace(); + callbackTag.comment = parseTagComments(indent); + + let child: JSDocParameterTag | false; + const start = scanner.getStartPos(); + const jsdocSignature = createNode(SyntaxKind.JSDocSignature, start) as JSDocSignature; + jsdocSignature.parameters = []; + while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter) as JSDocParameterTag)) { + jsdocSignature.parameters = append(jsdocSignature.parameters as MutableNodeArray, child); + } + const returnTag = tryParse(() => { + if (parseOptionalJsdoc(SyntaxKind.AtToken)) { + const tag = parseTag(indent); + if (tag && tag.kind === SyntaxKind.JSDocReturnTag) { + return tag as JSDocReturnTag; + } + } + }); + if (returnTag) { + jsdocSignature.type = returnTag; + } + callbackTag.typeExpression = finishNode(jsdocSignature); + return finishNode(callbackTag); + } + + function getJSDocTypeAliasName(fullName: JSDocNamespaceBody | undefined) { + if (fullName) { + let rightNode = fullName; + while (true) { + if (ts.isIdentifier(rightNode) || !rightNode.body) { + return ts.isIdentifier(rightNode) ? rightNode : rightNode.name; + } + rightNode = rightNode.body; + } + } + } + + function escapedTextsEqual(a: EntityName, b: EntityName): boolean { + while (!ts.isIdentifier(a) || !ts.isIdentifier(b)) { + if (!ts.isIdentifier(a) && !ts.isIdentifier(b) && a.right.escapedText === b.right.escapedText) { + a = a.left; + b = b.left; + } + else { + return false; + } + } + return a.escapedText === b.escapedText; + } + + function parseChildPropertyTag() { + return parseChildParameterOrPropertyTag(PropertyLikeParse.Property) as JSDocTypeTag | JSDocPropertyTag | false; + } + + function parseChildParameterOrPropertyTag(target: PropertyLikeParse, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false { + let canParseTag = true; + let seenAsterisk = false; + while (true) { + switch (nextJSDocToken()) { + case SyntaxKind.AtToken: + if (canParseTag) { + const child = tryParseChildTag(target); + if (child && (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) && + target !== PropertyLikeParse.CallbackParameter && + name && (ts.isIdentifier(child.name) || !escapedTextsEqual(name, child.name.left))) { + return false; + } + return child; + } + seenAsterisk = false; + break; + case SyntaxKind.NewLineTrivia: + canParseTag = true; + seenAsterisk = false; + break; + case SyntaxKind.AsteriskToken: + if (seenAsterisk) { + canParseTag = false; + } + seenAsterisk = true; + break; + case SyntaxKind.Identifier: + canParseTag = false; + break; + case SyntaxKind.EndOfFileToken: + return false; + } + } + } + + function tryParseChildTag(target: PropertyLikeParse): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false { + Debug.assert(token() === SyntaxKind.AtToken); + const atToken = createNode(SyntaxKind.AtToken); + atToken.end = scanner.getTextPos(); + nextJSDocToken(); + + const tagName = parseJSDocIdentifierName(); + skipWhitespace(); + let t: PropertyLikeParse; + switch (tagName.escapedText) { + case "type": + return target === PropertyLikeParse.Property && parseTypeTag(atToken, tagName); + case "prop": + case "property": + t = PropertyLikeParse.Property; + break; + case "arg": + case "argument": + case "param": + t = PropertyLikeParse.Parameter | PropertyLikeParse.CallbackParameter; + break; + default: + return false; + } + if (!(target & t)) { + return false; + } + const tag = parseParameterOrPropertyTag(atToken, tagName, target, /*indent*/ undefined); + tag.comment = parseTagComments(tag.end - tag.pos); + return tag; + } + + function parseTemplateTag(atToken: AtToken, tagName: Identifier): JSDocTemplateTag { + // the template tag looks like '@template {Constraint} T,U,V' + let constraint: JSDocTypeExpression | undefined; + if (token() === SyntaxKind.OpenBraceToken) { + constraint = parseJSDocTypeExpression(); + } + + const typeParameters = []; + const typeParametersPos = getNodePos(); + do { + skipWhitespace(); + const typeParameter = createNode(SyntaxKind.TypeParameter); + typeParameter.name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces); + finishNode(typeParameter); + skipWhitespace(); + typeParameters.push(typeParameter); + } while (parseOptionalJsdoc(SyntaxKind.CommaToken)); + + const result = createNode(SyntaxKind.JSDocTemplateTag, atToken.pos); + result.atToken = atToken; + result.tagName = tagName; + result.constraint = constraint; + result.typeParameters = createNodeArray(typeParameters, typeParametersPos); + finishNode(result); + return result; + } + + function nextJSDocToken(): JsDocSyntaxKind { + return currentToken = scanner.scanJSDocToken(); + } + + function parseOptionalJsdoc(t: JsDocSyntaxKind): boolean { + if (token() === t) { + nextJSDocToken(); + return true; + } + return false; + } + + function parseJSDocEntityName(): EntityName { + let entity: EntityName = parseJSDocIdentifierName(); + if (parseOptional(SyntaxKind.OpenBracketToken)) { + parseExpected(SyntaxKind.CloseBracketToken); + // Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking. + // Technically usejsdoc.org requires them for specifying a property of a type equivalent to Array<{ x: ...}> + // but it's not worth it to enforce that restriction. + } + while (parseOptional(SyntaxKind.DotToken)) { + const name = parseJSDocIdentifierName(); + if (parseOptional(SyntaxKind.OpenBracketToken)) { + parseExpected(SyntaxKind.CloseBracketToken); + } + entity = createQualifiedName(entity, name); + } + return entity; + } + + function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier { + if (!tokenIsIdentifierOrKeyword(token())) { + return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected); + } + + const pos = scanner.getTokenPos(); + const end = scanner.getTextPos(); + const result = createNode(SyntaxKind.Identifier, pos); + result.escapedText = escapeLeadingUnderscores(scanner.getTokenText()); + finishNode(result, end); + + nextJSDocToken(); + return result; + } + } + } + } + + namespace IncrementalParser { + export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean): SourceFile { + aggressiveChecks = aggressiveChecks || Debug.shouldAssert(AssertionLevel.Aggressive); + + checkChangeRange(sourceFile, newText, textChangeRange, aggressiveChecks); + if (textChangeRangeIsUnchanged(textChangeRange)) { + // if the text didn't change, then we can just return our current source file as-is. + return sourceFile; + } + + if (sourceFile.statements.length === 0) { + // If we don't have any statements in the current source file, then there's no real + // way to incrementally parse. So just do a full parse instead. + return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind); + } + + // Make sure we're not trying to incrementally update a source file more than once. Once + // we do an update the original source file is considered unusable from that point onwards. + // + // This is because we do incremental parsing in-place. i.e. we take nodes from the old + // tree and give them new positions and parents. From that point on, trusting the old + // tree at all is not possible as far too much of it may violate invariants. + const incrementalSourceFile = sourceFile; + Debug.assert(!incrementalSourceFile.hasBeenIncrementallyParsed); + incrementalSourceFile.hasBeenIncrementallyParsed = true; + + const oldText = sourceFile.text; + const syntaxCursor = createSyntaxCursor(sourceFile); + + // Make the actual change larger so that we know to reparse anything whose lookahead + // might have intersected the change. + const changeRange = extendToAffectedRange(sourceFile, textChangeRange); + checkChangeRange(sourceFile, newText, changeRange, aggressiveChecks); + + // Ensure that extending the affected range only moved the start of the change range + // earlier in the file. + Debug.assert(changeRange.span.start <= textChangeRange.span.start); + Debug.assert(textSpanEnd(changeRange.span) === textSpanEnd(textChangeRange.span)); + Debug.assert(textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange))); + + // The is the amount the nodes after the edit range need to be adjusted. It can be + // positive (if the edit added characters), negative (if the edit deleted characters) + // or zero (if this was a pure overwrite with nothing added/removed). + const delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length; + + // If we added or removed characters during the edit, then we need to go and adjust all + // the nodes after the edit. Those nodes may move forward (if we inserted chars) or they + // may move backward (if we deleted chars). + // + // Doing this helps us out in two ways. First, it means that any nodes/tokens we want + // to reuse are already at the appropriate position in the new text. That way when we + // reuse them, we don't have to figure out if they need to be adjusted. Second, it makes + // it very easy to determine if we can reuse a node. If the node's position is at where + // we are in the text, then we can reuse it. Otherwise we can't. If the node's position + // is ahead of us, then we'll need to rescan tokens. If the node's position is behind + // us, then we'll need to skip it or crumble it as appropriate + // + // We will also adjust the positions of nodes that intersect the change range as well. + // By doing this, we ensure that all the positions in the old tree are consistent, not + // just the positions of nodes entirely before/after the change range. By being + // consistent, we can then easily map from positions to nodes in the old tree easily. + // + // Also, mark any syntax elements that intersect the changed span. We know, up front, + // that we cannot reuse these elements. + updateTokenPositionsAndMarkElements(incrementalSourceFile, + changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks); + + // Now that we've set up our internal incremental state just proceed and parse the + // source file in the normal fashion. When possible the parser will retrieve and + // reuse nodes from the old tree. + // + // Note: passing in 'true' for setNodeParents is very important. When incrementally + // parsing, we will be reusing nodes from the old tree, and placing it into new + // parents. If we don't set the parents now, we'll end up with an observably + // inconsistent tree. Setting the parents on the new tree should be very fast. We + // will immediately bail out of walking any subtrees when we can see that their parents + // are already correct. + const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind); + + return result; + } + + function moveElementEntirelyPastChangeRange(element: IncrementalElement, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) { + if (isArray) { + visitArray(element); + } + else { + visitNode(element); + } + return; + + function visitNode(node: IncrementalNode) { + let text = ""; + if (aggressiveChecks && shouldCheckNode(node)) { + text = oldText.substring(node.pos, node.end); + } + + // Ditch any existing LS children we may have created. This way we can avoid + // moving them forward. + if (node._children) { + node._children = undefined; + } + + node.pos += delta; + node.end += delta; + + if (aggressiveChecks && shouldCheckNode(node)) { + Debug.assert(text === newText.substring(node.pos, node.end)); + } + + forEachChild(node, visitNode, visitArray); + if (hasJSDocNodes(node)) { + for (const jsDocComment of node.jsDoc!) { + visitNode(jsDocComment); + } + } + checkNodePositions(node, aggressiveChecks); + } + + function visitArray(array: IncrementalNodeArray) { + array._children = undefined; + array.pos += delta; + array.end += delta; + + for (const node of array) { + visitNode(node); + } + } + } + + function shouldCheckNode(node: Node) { + switch (node.kind) { + case SyntaxKind.StringLiteral: + case SyntaxKind.NumericLiteral: + case SyntaxKind.Identifier: + return true; + } + + return false; + } + + function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) { + Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range"); + Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range"); + Debug.assert(element.pos <= element.end); + + // We have an element that intersects the change range in some way. It may have its + // start, or its end (or both) in the changed range. We want to adjust any part + // that intersects such that the final tree is in a consistent state. i.e. all + // children have spans within the span of their parent, and all siblings are ordered + // properly. + + // We may need to update both the 'pos' and the 'end' of the element. + + // If the 'pos' is before the start of the change, then we don't need to touch it. + // If it isn't, then the 'pos' must be inside the change. How we update it will + // depend if delta is positive or negative. If delta is positive then we have + // something like: + // + // -------------------AAA----------------- + // -------------------BBBCCCCCCC----------------- + // + // In this case, we consider any node that started in the change range to still be + // starting at the same position. + // + // however, if the delta is negative, then we instead have something like this: + // + // -------------------XXXYYYYYYY----------------- + // -------------------ZZZ----------------- + // + // In this case, any element that started in the 'X' range will keep its position. + // However any element that started after that will have their pos adjusted to be + // at the end of the new range. i.e. any node that started in the 'Y' range will + // be adjusted to have their start at the end of the 'Z' range. + // + // The element will keep its position if possible. Or Move backward to the new-end + // if it's in the 'Y' range. + element.pos = Math.min(element.pos, changeRangeNewEnd); + + // If the 'end' is after the change range, then we always adjust it by the delta + // amount. However, if the end is in the change range, then how we adjust it + // will depend on if delta is positive or negative. If delta is positive then we + // have something like: + // + // -------------------AAA----------------- + // -------------------BBBCCCCCCC----------------- + // + // In this case, we consider any node that ended inside the change range to keep its + // end position. + // + // however, if the delta is negative, then we instead have something like this: + // + // -------------------XXXYYYYYYY----------------- + // -------------------ZZZ----------------- + // + // In this case, any element that ended in the 'X' range will keep its position. + // However any element that ended after that will have their pos adjusted to be + // at the end of the new range. i.e. any node that ended in the 'Y' range will + // be adjusted to have their end at the end of the 'Z' range. + if (element.end >= changeRangeOldEnd) { + // Element ends after the change range. Always adjust the end pos. + element.end += delta; + } + else { + // Element ends in the change range. The element will keep its position if + // possible. Or Move backward to the new-end if it's in the 'Y' range. + element.end = Math.min(element.end, changeRangeNewEnd); + } + + Debug.assert(element.pos <= element.end); + if (element.parent) { + Debug.assert(element.pos >= element.parent.pos); + Debug.assert(element.end <= element.parent.end); + } + } + + function checkNodePositions(node: Node, aggressiveChecks: boolean) { + if (aggressiveChecks) { + let pos = node.pos; + const visitNode = (child: Node) => { + Debug.assert(child.pos >= pos); + pos = child.end; + }; + if (hasJSDocNodes(node)) { + for (const jsDocComment of node.jsDoc!) { + visitNode(jsDocComment); + } + } + forEachChild(node, visitNode); + Debug.assert(pos <= node.end); + } + } + + function updateTokenPositionsAndMarkElements( + sourceFile: IncrementalNode, + changeStart: number, + changeRangeOldEnd: number, + changeRangeNewEnd: number, + delta: number, + oldText: string, + newText: string, + aggressiveChecks: boolean): void { + + visitNode(sourceFile); + return; + + function visitNode(child: IncrementalNode) { + Debug.assert(child.pos <= child.end); + if (child.pos > changeRangeOldEnd) { + // Node is entirely past the change range. We need to move both its pos and + // end, forward or backward appropriately. + moveElementEntirelyPastChangeRange(child, /*isArray*/ false, delta, oldText, newText, aggressiveChecks); + return; + } + + // Check if the element intersects the change range. If it does, then it is not + // reusable. Also, we'll need to recurse to see what constituent portions we may + // be able to use. + const fullEnd = child.end; + if (fullEnd >= changeStart) { + child.intersectsChange = true; + child._children = undefined; + + // Adjust the pos or end (or both) of the intersecting element accordingly. + adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); + forEachChild(child, visitNode, visitArray); + if (hasJSDocNodes(child)) { + for (const jsDocComment of child.jsDoc!) { + visitNode(jsDocComment); + } + } + checkNodePositions(child, aggressiveChecks); + return; + } + + // Otherwise, the node is entirely before the change range. No need to do anything with it. + Debug.assert(fullEnd < changeStart); + } + + function visitArray(array: IncrementalNodeArray) { + Debug.assert(array.pos <= array.end); + if (array.pos > changeRangeOldEnd) { + // Array is entirely after the change range. We need to move it, and move any of + // its children. + moveElementEntirelyPastChangeRange(array, /*isArray*/ true, delta, oldText, newText, aggressiveChecks); + return; + } + + // Check if the element intersects the change range. If it does, then it is not + // reusable. Also, we'll need to recurse to see what constituent portions we may + // be able to use. + const fullEnd = array.end; + if (fullEnd >= changeStart) { + array.intersectsChange = true; + array._children = undefined; + + // Adjust the pos or end (or both) of the intersecting array accordingly. + adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); + for (const node of array) { + visitNode(node); + } + return; + } + + // Otherwise, the array is entirely before the change range. No need to do anything with it. + Debug.assert(fullEnd < changeStart); + } + } + + function extendToAffectedRange(sourceFile: SourceFile, changeRange: TextChangeRange): TextChangeRange { + // Consider the following code: + // void foo() { /; } + // + // If the text changes with an insertion of / just before the semicolon then we end up with: + // void foo() { //; } + // + // If we were to just use the changeRange a is, then we would not rescan the { token + // (as it does not intersect the actual original change range). Because an edit may + // change the token touching it, we actually need to look back *at least* one token so + // that the prior token sees that change. + const maxLookahead = 1; + + let start = changeRange.span.start; + + // the first iteration aligns us with the change start. subsequent iteration move us to + // the left by maxLookahead tokens. We only need to do this as long as we're not at the + // start of the tree. + for (let i = 0; start > 0 && i <= maxLookahead; i++) { + const nearestNode = findNearestNodeStartingBeforeOrAtPosition(sourceFile, start); + Debug.assert(nearestNode.pos <= start); + const position = nearestNode.pos; + + start = Math.max(0, position - 1); + } + + const finalSpan = createTextSpanFromBounds(start, textSpanEnd(changeRange.span)); + const finalLength = changeRange.newLength + (changeRange.span.start - start); + + return createTextChangeRange(finalSpan, finalLength); + } + + function findNearestNodeStartingBeforeOrAtPosition(sourceFile: SourceFile, position: number): Node { + let bestResult: Node = sourceFile; + let lastNodeEntirelyBeforePosition: Node | undefined; + + forEachChild(sourceFile, visit); + + if (lastNodeEntirelyBeforePosition) { + const lastChildOfLastEntireNodeBeforePosition = getLastDescendant(lastNodeEntirelyBeforePosition); + if (lastChildOfLastEntireNodeBeforePosition.pos > bestResult.pos) { + bestResult = lastChildOfLastEntireNodeBeforePosition; + } + } + + return bestResult; + + function getLastDescendant(node: Node): Node { + while (true) { + const lastChild = getLastChild(node); + if (lastChild) { + node = lastChild; + } + else { + return node; + } + } + } + + function visit(child: Node) { + if (nodeIsMissing(child)) { + // Missing nodes are effectively invisible to us. We never even consider them + // When trying to find the nearest node before us. + return; + } + + // If the child intersects this position, then this node is currently the nearest + // node that starts before the position. + if (child.pos <= position) { + if (child.pos >= bestResult.pos) { + // This node starts before the position, and is closer to the position than + // the previous best node we found. It is now the new best node. + bestResult = child; + } + + // Now, the node may overlap the position, or it may end entirely before the + // position. If it overlaps with the position, then either it, or one of its + // children must be the nearest node before the position. So we can just + // recurse into this child to see if we can find something better. + if (position < child.end) { + // The nearest node is either this child, or one of the children inside + // of it. We've already marked this child as the best so far. Recurse + // in case one of the children is better. + forEachChild(child, visit); + + // Once we look at the children of this node, then there's no need to + // continue any further. + return true; + } + else { + Debug.assert(child.end <= position); + // The child ends entirely before this position. Say you have the following + // (where $ is the position) + // + // ? $ : <...> <...> + // + // We would want to find the nearest preceding node in "complex expr 2". + // To support that, we keep track of this node, and once we're done searching + // for a best node, we recurse down this node to see if we can find a good + // result in it. + // + // This approach allows us to quickly skip over nodes that are entirely + // before the position, while still allowing us to find any nodes in the + // last one that might be what we want. + lastNodeEntirelyBeforePosition = child; + } + } + else { + Debug.assert(child.pos > position); + // We're now at a node that is entirely past the position we're searching for. + // This node (and all following nodes) could never contribute to the result, + // so just skip them by returning 'true' here. + return true; + } + } + } + + function checkChangeRange(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean) { + const oldText = sourceFile.text; + if (textChangeRange) { + Debug.assert((oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length); + + if (aggressiveChecks || Debug.shouldAssert(AssertionLevel.VeryAggressive)) { + const oldTextPrefix = oldText.substr(0, textChangeRange.span.start); + const newTextPrefix = newText.substr(0, textChangeRange.span.start); + Debug.assert(oldTextPrefix === newTextPrefix); + + const oldTextSuffix = oldText.substring(textSpanEnd(textChangeRange.span), oldText.length); + const newTextSuffix = newText.substring(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.length); + Debug.assert(oldTextSuffix === newTextSuffix); + } + } + } + + interface IncrementalElement extends TextRange { + parent: Node; + intersectsChange: boolean; + length?: number; + _children: Node[] | undefined; + } + + export interface IncrementalNode extends Node, IncrementalElement { + hasBeenIncrementallyParsed: boolean; + } + + interface IncrementalNodeArray extends NodeArray, IncrementalElement { + length: number; + } + + // Allows finding nodes in the source file at a certain position in an efficient manner. + // The implementation takes advantage of the calling pattern it knows the parser will + // make in order to optimize finding nodes as quickly as possible. + export interface SyntaxCursor { + currentNode(position: number): IncrementalNode; + } + + function createSyntaxCursor(sourceFile: SourceFile): SyntaxCursor { + let currentArray: NodeArray = sourceFile.statements; + let currentArrayIndex = 0; + + Debug.assert(currentArrayIndex < currentArray.length); + let current = currentArray[currentArrayIndex]; + let lastQueriedPosition = InvalidPosition.Value; + + return { + currentNode(position: number) { + // Only compute the current node if the position is different than the last time + // we were asked. The parser commonly asks for the node at the same position + // twice. Once to know if can read an appropriate list element at a certain point, + // and then to actually read and consume the node. + if (position !== lastQueriedPosition) { + // Much of the time the parser will need the very next node in the array that + // we just returned a node from.So just simply check for that case and move + // forward in the array instead of searching for the node again. + if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) { + currentArrayIndex++; + current = currentArray[currentArrayIndex]; + } + + // If we don't have a node, or the node we have isn't in the right position, + // then try to find a viable node at the position requested. + if (!current || current.pos !== position) { + findHighestListElementThatStartsAtPosition(position); + } + } + + // Cache this query so that we don't do any extra work if the parser calls back + // into us. Note: this is very common as the parser will make pairs of calls like + // 'isListElement -> parseListElement'. If we were unable to find a node when + // called with 'isListElement', we don't want to redo the work when parseListElement + // is called immediately after. + lastQueriedPosition = position; + + // Either we don'd have a node, or we have a node at the position being asked for. + Debug.assert(!current || current.pos === position); + return current; + } + }; + + // Finds the highest element in the tree we can find that starts at the provided position. + // The element must be a direct child of some node list in the tree. This way after we + // return it, we can easily return its next sibling in the list. + function findHighestListElementThatStartsAtPosition(position: number) { + // Clear out any cached state about the last node we found. + currentArray = undefined!; + currentArrayIndex = InvalidPosition.Value; + current = undefined!; + + // Recurse into the source file to find the highest node at this position. + forEachChild(sourceFile, visitNode, visitArray); + return; + + function visitNode(node: Node) { + if (position >= node.pos && position < node.end) { + // Position was within this node. Keep searching deeper to find the node. + forEachChild(node, visitNode, visitArray); + + // don't proceed any further in the search. + return true; + } + + // position wasn't in this node, have to keep searching. + return false; + } + + function visitArray(array: NodeArray) { + if (position >= array.pos && position < array.end) { + // position was in this array. Search through this array to see if we find a + // viable element. + for (let i = 0; i < array.length; i++) { + const child = array[i]; + if (child) { + if (child.pos === position) { + // Found the right node. We're done. + currentArray = array; + currentArrayIndex = i; + current = child; + return true; + } + else { + if (child.pos < position && position < child.end) { + // Position in somewhere within this child. Search in it and + // stop searching in this array. + forEachChild(child, visitNode, visitArray); + return true; + } + } + } + } + } + + // position wasn't in this array, have to keep searching. + return false; + } + } + } + + const enum InvalidPosition { + Value = -1 + } + } + + /** @internal */ + export function isDeclarationFileName(fileName: string): boolean { + return fileExtensionIs(fileName, Extension.Dts); + } + + /*@internal*/ + export interface PragmaContext { + languageVersion: ScriptTarget; + pragmas?: PragmaMap; + checkJsDirective?: CheckJsDirective; + referencedFiles: FileReference[]; + typeReferenceDirectives: FileReference[]; + libReferenceDirectives: FileReference[]; + amdDependencies: AmdDependency[]; + hasNoDefaultLib?: boolean; + moduleName?: string; + } + + /*@internal*/ + export function processCommentPragmas(context: PragmaContext, sourceText: string): void { + const triviaScanner = createScanner(context.languageVersion, /*skipTrivia*/ false, LanguageVariant.Standard, sourceText); + const pragmas: PragmaPsuedoMapEntry[] = []; + + // Keep scanning all the leading trivia in the file until we get to something that + // isn't trivia. Any single line comment will be analyzed to see if it is a + // reference comment. + while (true) { + const kind = triviaScanner.scan(); + if (!isTrivia(kind)) { + break; + } + + const range = { + kind: triviaScanner.getToken(), + pos: triviaScanner.getTokenPos(), + end: triviaScanner.getTextPos(), + }; + + const comment = sourceText.substring(range.pos, range.end); + extractPragmas(pragmas, range, comment); + } + + context.pragmas = createMap() as PragmaMap; + for (const pragma of pragmas) { + if (context.pragmas.has(pragma!.name)) { // TODO: GH#18217 + const currentValue = context.pragmas.get(pragma!.name); + if (currentValue instanceof Array) { + currentValue.push(pragma!.args); + } + else { + context.pragmas.set(pragma!.name, [currentValue, pragma!.args]); + } + continue; + } + context.pragmas.set(pragma!.name, pragma!.args); + } + } + + /*@internal*/ + type PragmaDiagnosticReporter = (pos: number, length: number, message: DiagnosticMessage) => void; + + /*@internal*/ + export function processPragmasIntoFields(context: PragmaContext, reportDiagnostic: PragmaDiagnosticReporter): void { + context.checkJsDirective = undefined; + context.referencedFiles = []; + context.typeReferenceDirectives = []; + context.libReferenceDirectives = []; + context.amdDependencies = []; + context.hasNoDefaultLib = false; + context.pragmas!.forEach((entryOrList, key) => { // TODO: GH#18217 + // TODO: The below should be strongly type-guarded and not need casts/explicit annotations, since entryOrList is related to + // key and key is constrained to a union; but it's not (see GH#21483 for at least partial fix) :( + switch (key) { + case "reference": { + const referencedFiles = context.referencedFiles; + const typeReferenceDirectives = context.typeReferenceDirectives; + const libReferenceDirectives = context.libReferenceDirectives; + forEach(toArray(entryOrList), (arg: PragmaPsuedoMap["reference"]) => { + // TODO: GH#18217 + if (arg!.arguments["no-default-lib"]) { + context.hasNoDefaultLib = true; + } + else if (arg!.arguments.types) { + typeReferenceDirectives.push({ pos: arg!.arguments.types!.pos, end: arg!.arguments.types!.end, fileName: arg!.arguments.types!.value }); + } + else if (arg!.arguments.lib) { + libReferenceDirectives.push({ pos: arg!.arguments.lib!.pos, end: arg!.arguments.lib!.end, fileName: arg!.arguments.lib!.value }); + } + else if (arg!.arguments.path) { + referencedFiles.push({ pos: arg!.arguments.path!.pos, end: arg!.arguments.path!.end, fileName: arg!.arguments.path!.value }); + } + else { + reportDiagnostic(arg!.range.pos, arg!.range.end - arg!.range.pos, Diagnostics.Invalid_reference_directive_syntax); + } + }); + break; + } + case "amd-dependency": { + context.amdDependencies = map( + toArray(entryOrList), + (x: PragmaPsuedoMap["amd-dependency"]) => ({ name: x!.arguments.name!, path: x!.arguments.path })); // TODO: GH#18217 + break; + } + case "amd-module": { + if (entryOrList instanceof Array) { + for (const entry of entryOrList) { + if (context.moduleName) { + // TODO: It's probably fine to issue this diagnostic on all instances of the pragma + reportDiagnostic(entry!.range.pos, entry!.range.end - entry!.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments); + } + context.moduleName = (entry as PragmaPsuedoMap["amd-module"])!.arguments.name; + } + } + else { + context.moduleName = (entryOrList as PragmaPsuedoMap["amd-module"])!.arguments.name; + } + break; + } + case "ts-nocheck": + case "ts-check": { + // _last_ of either nocheck or check in a file is the "winner" + forEach(toArray(entryOrList), entry => { + if (!context.checkJsDirective || entry!.range.pos > context.checkJsDirective.pos) { // TODO: GH#18217 + context.checkJsDirective = { + enabled: key === "ts-check", + end: entry!.range.end, + pos: entry!.range.pos + }; + } + }); + break; + } + case "jsx": return; // Accessed directly + default: Debug.fail("Unhandled pragma kind"); // Can this be made into an assertNever in the future? + } + }); + } + + const namedArgRegExCache = createMap(); + function getNamedArgRegEx(name: string): RegExp { + if (namedArgRegExCache.has(name)) { + return namedArgRegExCache.get(name)!; + } + const result = new RegExp(`(\\s${name}\\s*=\\s*)('|")(.+?)\\2`, "im"); + namedArgRegExCache.set(name, result); + return result; + } + + const tripleSlashXMLCommentStartRegEx = /^\/\/\/\s*<(\S+)\s.*?\/>/im; + const singleLinePragmaRegEx = /^\/\/\/?\s*@(\S+)\s*(.*)\s*$/im; + function extractPragmas(pragmas: PragmaPsuedoMapEntry[], range: CommentRange, text: string) { + const tripleSlash = range.kind === SyntaxKind.SingleLineCommentTrivia && tripleSlashXMLCommentStartRegEx.exec(text); + if (tripleSlash) { + const name = tripleSlash[1].toLowerCase() as keyof PragmaPsuedoMap; // Technically unsafe cast, but we do it so the below check to make it safe typechecks + const pragma = commentPragmas[name] as PragmaDefinition; + if (!pragma || !(pragma.kind! & PragmaKindFlags.TripleSlashXML)) { + return; + } + if (pragma.args) { + const argument: {[index: string]: string | {value: string, pos: number, end: number}} = {}; + for (const arg of pragma.args) { + const matcher = getNamedArgRegEx(arg.name); + const matchResult = matcher.exec(text); + if (!matchResult && !arg.optional) { + return; // Missing required argument, don't parse + } + else if (matchResult) { + if (arg.captureSpan) { + const startPos = range.pos + matchResult.index + matchResult[1].length + matchResult[2].length; + argument[arg.name] = { + value: matchResult[3], + pos: startPos, + end: startPos + matchResult[3].length + }; + } + else { + argument[arg.name] = matchResult[3]; + } + } + } + pragmas.push({ name, args: { arguments: argument, range } } as PragmaPsuedoMapEntry); + } + else { + pragmas.push({ name, args: { arguments: {}, range } } as PragmaPsuedoMapEntry); + } + return; + } + + const singleLine = range.kind === SyntaxKind.SingleLineCommentTrivia && singleLinePragmaRegEx.exec(text); + if (singleLine) { + return addPragmaForMatch(pragmas, range, PragmaKindFlags.SingleLine, singleLine); + } + + if (range.kind === SyntaxKind.MultiLineCommentTrivia) { + const multiLinePragmaRegEx = /\s*@(\S+)\s*(.*)\s*$/gim; // Defined inline since it uses the "g" flag, which keeps a persistent index (for iterating) + let multiLineMatch: RegExpExecArray | null; + while (multiLineMatch = multiLinePragmaRegEx.exec(text)) { + addPragmaForMatch(pragmas, range, PragmaKindFlags.MultiLine, multiLineMatch); + } + } + } + + function addPragmaForMatch(pragmas: PragmaPsuedoMapEntry[], range: CommentRange, kind: PragmaKindFlags, match: RegExpExecArray) { + if (!match) return; + const name = match[1].toLowerCase() as keyof PragmaPsuedoMap; // Technically unsafe cast, but we do it so they below check to make it safe typechecks + const pragma = commentPragmas[name] as PragmaDefinition; + if (!pragma || !(pragma.kind! & kind)) { + return; + } + const args = match[2]; // Split on spaces and match up positionally with definition + const argument = getNamedPragmaArguments(pragma, args); + if (argument === "fail") return; // Missing required argument, fail to parse it + pragmas.push({ name, args: { arguments: argument, range } } as PragmaPsuedoMapEntry); + return; + } + + function getNamedPragmaArguments(pragma: PragmaDefinition, text: string | undefined): {[index: string]: string} | "fail" { + if (!text) return {}; + if (!pragma.args) return {}; + const args = text.split(/\s+/); + const argMap: {[index: string]: string} = {}; + for (let i = 0; i < pragma.args.length; i++) { + const argument = pragma.args[i]; + if (!args[i] && !argument.optional) { + return "fail"; + } + if (argument.captureSpan) { + return Debug.fail("Capture spans not yet implemented for non-xml pragmas"); + } + argMap[argument.name] = args[i]; + } + return argMap; + } + + /** @internal */ + export function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean { + if (lhs.kind !== rhs.kind) { + return false; + } + + if (lhs.kind === SyntaxKind.Identifier) { + return lhs.escapedText === (rhs).escapedText; + } + + if (lhs.kind === SyntaxKind.ThisKeyword) { + return true; + } + + // If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only + // take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression + // it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element + return (lhs).name.escapedText === (rhs).name.escapedText && + tagNamesAreEquivalent((lhs).expression as JsxTagNameExpression, (rhs).expression as JsxTagNameExpression); + } +} \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index 223a76f..0000000 --- a/gulpfile.js +++ /dev/null @@ -1,15 +0,0 @@ -const gulp = require('gulp'); -const mocha = require('gulp-mocha'); -const eslint = require('gulp-eslint'); - -// gulp.task('eslint', () => gulp -// .src(['**/*.js', '!node_modules/**']) -// .pipe(eslint()) -// .pipe(eslint.format()) -// .pipe(eslint.failAfterError())); - -gulp.task('mocha', () => gulp - .src('test/*.js', { read: false }) - .pipe(mocha())); - -gulp.task('default', ['mocha']); diff --git a/index.js b/index.js deleted file mode 100644 index f4b999d..0000000 --- a/index.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; -Object.defineProperty(exports, "__esModule", { value: true }); -const index_1 = require("./src/javascript/index"); -class Parser { - constructor(options) { - this.options = options; - } - /** - * @param file: IFile - * @return IParseResult - */ - parse(file) { - switch (this.options.language) { - case 'js': - case 'javascript': - return (new index_1.default().parse(file)); - default: - return { type: '', file: { name: '', source: '' }, comments: [] }; - } - } -} -exports.default = Parser; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/index.js.map b/index.js.map deleted file mode 100644 index d4676ee..0000000 --- a/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AACb,kDAAgD;AAGhD;IAIE,YAAY,OAAY;QACtB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IACD;;;OAGG;IACH,KAAK,CAAC,IAAW;QACf,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC9B,KAAK,IAAI,CAAC;YACV,KAAK,YAAY;gBACf,MAAM,CAAC,CAAC,IAAI,eAAU,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YACxC;gBACE,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACtE,CAAC;IACH,CAAC;CACF;AApBD,yBAoBC"} \ No newline at end of file diff --git a/index.ts b/index.ts index 3d349c5..4aed94c 100644 --- a/index.ts +++ b/index.ts @@ -1,27 +1,38 @@ -'use strict'; -import JavaScript from './src/javascript/index'; -import { IParser, IParseResult, IFile } from './src/interface'; +import Source from './src/interfaces/Source'; +import ParserFactory from './src/ParserFactory'; +import Parser from './src/lang/common/parser'; +import { Tree } from 'tree-sitter'; -export default class Parser implements IParser { - private options: { - language: string, +/** + * A class that parses a source code and generates an AST. + * + * @class Parser + * @implements IParser + * + * # Example + * + * ```js + * const parser = new Parser({ + * name: '...', + * path: '....', + * text: '...' + * }, { language: 'typescript' }); + * + * const result = parser.parse(); + * + * ``` + */ +export default class DocParser extends Parser { + + private parser: Parser; + constructor(source: Source, options?: object) { + super(source, options) + this.parser = (new ParserFactory(this.source, this.options)).getParser(); } - constructor(options: any) { - this.options = options; + parse = () => { + return this.parser.parse() } - /** - * @param file: IFile - * @return IParseResult - */ - parse(file: IFile): IParseResult { - switch (this.options.language) { - case 'js': - case 'javascript': - return (new JavaScript().parse(file)); - default: - return { type: '', file: { name: '', source: '' }, comments: [] }; - } + get tree (): Tree { + return this.parser.tree; } } - -export * from './src/interface'; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3d58d28..669b465 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,149 +5,72 @@ "requires": true, "dependencies": { "@types/babel-core": { - "version": "6.25.3", - "resolved": "https://registry.npmjs.org/@types/babel-core/-/babel-core-6.25.3.tgz", - "integrity": "sha512-OlUjfM+Qv+XwcaucEiekBIhfAYe4q4ruvQZZcCkOtQZ27Hykxm1LLY2s0mE6LtP9XQt6x+TUvS70KW2e8Mz0ZA==", + "version": "6.25.5", + "resolved": "https://registry.npmjs.org/@types/babel-core/-/babel-core-6.25.5.tgz", + "integrity": "sha512-pecvyMrc46zY0AFYXVZWNmm/gekr7f32OBYCd9baOiIpOTFtNN0ormeWpJaG7p+MEzncUvNtJdYql94dZYZGsw==", "requires": { - "@types/babel-generator": "6.25.1", - "@types/babel-template": "6.25.0", - "@types/babel-traverse": "6.25.3", - "@types/babel-types": "7.0.0", - "@types/babylon": "6.16.2" + "@types/babel-generator": "*", + "@types/babel-template": "*", + "@types/babel-traverse": "*", + "@types/babel-types": "*", + "@types/babylon": "*" } }, "@types/babel-generator": { - "version": "6.25.1", - "resolved": "https://registry.npmjs.org/@types/babel-generator/-/babel-generator-6.25.1.tgz", - "integrity": "sha512-nKNz9Ch4WP2TFZjQROhxqqS2SCk0OoDzGazJI6S+2sGgW9P7N4o3vluZAXFuPEnRqtz2A0vrrkK3tjQktxIlRw==", + "version": "6.25.2", + "resolved": "https://registry.npmjs.org/@types/babel-generator/-/babel-generator-6.25.2.tgz", + "integrity": "sha512-W7PQkeDlYOqJblfNeqZARwj4W8nO+ZhQQZksU8+wbaKuHeUdIVUAdREO/Qb0FfNr3CY5Sq1gNtqsyFeZfS3iSw==", "requires": { - "@types/babel-types": "7.0.0" + "@types/babel-types": "*" } }, "@types/babel-template": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/@types/babel-template/-/babel-template-6.25.0.tgz", - "integrity": "sha512-TtyfVlrprX92xSuKa8D//7vFz5kBJODBw5IQ1hQXehqO+me26vt1fyNxOZyXhUq2a7jRyT72V8p68IyH4NEZNA==", + "version": "6.25.1", + "resolved": "https://registry.npmjs.org/@types/babel-template/-/babel-template-6.25.1.tgz", + "integrity": "sha512-teJYxh35PbBaf9OY6YwLSQ7pRiWRnHCHmlqwfVSfexOsqHUf6hpNZ4FG9PfgnpBM1VRzRJVQF3SqqOtkcNrBZQ==", "requires": { - "@types/babel-types": "7.0.0", - "@types/babylon": "6.16.2" + "@types/babel-types": "*", + "@types/babylon": "*" } }, "@types/babel-traverse": { - "version": "6.25.3", - "resolved": "https://registry.npmjs.org/@types/babel-traverse/-/babel-traverse-6.25.3.tgz", - "integrity": "sha512-4FaulWyA7nrXPkzoukL2VmSpxCnBZwc+MgwZqO30gtHCrtaUXnoxymdYfxzf3CZN80zjtrVzKfLlZ7FPYvrhQQ==", + "version": "6.25.4", + "resolved": "https://registry.npmjs.org/@types/babel-traverse/-/babel-traverse-6.25.4.tgz", + "integrity": "sha512-+/670NaZE7qPvdh8EtGds32/2uHFKE5JeS+7ePH6nGwF8Wj8r671/RkTiJQP2k22nFntWEb9xQ11MFj7xEqI0g==", "requires": { - "@types/babel-types": "7.0.0" + "@types/babel-types": "*" } }, "@types/babel-types": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.0.tgz", - "integrity": "sha512-PyWcbX0W4r4GcgXLI0Vu4jyJ/Erueo3PwjgvQcOmWAOBW0ObhzBBciEX+sHvjkNE0umI6nqD192FDKvYZTL91A==" + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.4.tgz", + "integrity": "sha512-WiZhq3SVJHFRgRYLXvpf65XnV6ipVHhnNaNvE8yCimejrGglkg38kEj0JcizqwSHxmPSjcTlig/6JouxLGEhGw==" }, "@types/babylon": { - "version": "6.16.2", - "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.2.tgz", - "integrity": "sha512-+Jty46mPaWe1VAyZbfvgJM4BAdklLWxrT5tc/RjvCgLrtk6gzRY6AOnoWFv4p6hVxhJshDdr2hGVn56alBp97Q==", + "version": "6.16.3", + "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.3.tgz", + "integrity": "sha512-lyJ8sW1PbY3uwuvpOBZ9zMYKshMnQpXmeDHh8dj9j2nJm/xrW0FgB5gLSYOArj5X0IfaXnmhFoJnhS4KbqIMug==", "requires": { - "@types/babel-types": "7.0.0" + "@types/babel-types": "*" } }, "@types/lodash": { - "version": "4.14.91", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.91.tgz", - "integrity": "sha512-k+nc3moSlAaXacyvz4/c6D9lnUeI6AKsLvkXFuNzUEEqMw7sjDnLW2GqlJ4nyFgMX/p+QzvVG6zRoDo4lJIV5g==" + "version": "4.14.116", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.116.tgz", + "integrity": "sha512-lRnAtKnxMXcYYXqOiotTmJd74uawNWuPnsnPrrO7HiFuE3npE2iQhfABatbYDyxTNqZNuXzcKGhw37R7RjBFLg==" }, "@types/mocha": { - "version": "2.2.45", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.45.tgz", - "integrity": "sha512-tE1SYtNG3I3atRVPELSGN2FJJJtPg3O/G0tycYSyzeDqdAbdLPRH089LhpWYA5M/iHeWHkVZq/b0OVKngcK0Eg==", - "dev": true, - "requires": { - "@types/node": "8.5.5" - } - }, - "@types/node": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.5.tgz", - "integrity": "sha512-JRnfoh0Ll4ElmIXKxbUfcOodkGvcNHljct6mO1X9hE/mlrMzAx0hYCLAD7sgT53YAY1HdlpzUcV0CkmDqUqTuA==", - "dev": true - }, - "acorn": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.3.0.tgz", - "integrity": "sha512-Yej+zOJ1Dm/IMZzzj78OntP/r3zHEaKcyNoU2lAaxPtrseM6rF0xwqoz5Q5ysAiED9hTjI2hgtvLXitlCN1/Ug==", - "dev": true - }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "dev": true, - "requires": { - "acorn": "3.3.0" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - } - } - }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.0.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - } - }, - "ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "version": "2.2.48", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.48.tgz", + "integrity": "sha512-nlK/iyETgafGli8Zh9zJVCTicvU3iajSkRwOh3Hhiva598CMqNJ4NcVCGMTGKpGpTYj/9R8RLzS9NAykSSCqGw==", "dev": true }, - "ansi-cyan": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", - "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", - "dev": true, - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-escapes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", - "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==", + "@types/node": { + "version": "8.10.28", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.28.tgz", + "integrity": "sha512-iHsAzDg3OLH7JP+wipniUULHoDSWLgEDYOvsar6/mpAkTJd9/n23Ap8ikruMlvRTqMv/LXrflH9v/AfiEqaBGg==", "dev": true }, - "ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", - "dev": true, - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-red": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", - "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", - "dev": true, - "requires": { - "ansi-wrap": "0.1.0" - } - }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -158,209 +81,89 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, - "ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", - "dev": true - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "argparse": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", - "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", - "dev": true, - "requires": { - "sprintf-js": "1.0.3" - } - }, - "aria-query": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-0.7.0.tgz", - "integrity": "sha512-/r2lHl09V3o74+2MLKEdewoj37YZqiQZnfen1O4iNlrOjUgeKuu1U2yF3iKh6HJxqF+OXkLMfQv65Z/cvxD6vA==", - "dev": true, - "requires": { - "ast-types-flow": "0.0.7" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", - "dev": true - }, - "array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", - "dev": true - }, - "array-includes": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", - "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", - "dev": true, - "requires": { - "define-properties": "1.1.2", - "es-abstract": "1.10.0" - } + "antlr4ts": { + "version": "0.4.1-alpha.0", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.4.1-alpha.0.tgz", + "integrity": "sha1-rFcX8w8++jYXsATo/0+GC5x9TSA=" }, - "array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", - "dev": true + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "requires": { - "array-uniq": "1.0.3" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true - }, "assertion-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", - "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", - "dev": true - }, - "atob": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.0.3.tgz", - "integrity": "sha1-GcenYEc3dEaPILLS0DNyrX1Mv10=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, - "axobject-query": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-0.1.0.tgz", - "integrity": "sha1-YvWdvFnJ+SQnWco0mWDnov48NsA=", - "dev": true, - "requires": { - "ast-types-flow": "0.0.7" - } - }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" } }, "babel-core": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", - "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", - "dev": true, - "requires": { - "babel-code-frame": "6.26.0", - "babel-generator": "6.26.0", - "babel-helpers": "6.24.1", - "babel-messages": "6.23.0", - "babel-register": "6.26.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "convert-source-map": "1.5.1", - "debug": "2.6.9", - "json5": "0.5.1", - "lodash": "4.17.4", - "minimatch": "3.0.4", - "path-is-absolute": "1.0.1", - "private": "0.1.8", - "slash": "1.0.0", - "source-map": "0.5.7" + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "requires": { + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" } }, "babel-generator": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz", - "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=", - "dev": true, + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", "requires": { - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "detect-indent": "4.0.0", - "jsesc": "1.3.0", - "lodash": "4.17.4", - "source-map": "0.5.7", - "trim-right": "1.0.1" + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" } }, "babel-helpers": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" } }, "babel-messages": { @@ -368,22 +171,21 @@ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" } }, "babel-register": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "dev": true, "requires": { - "babel-core": "6.26.0", - "babel-runtime": "6.26.0", - "core-js": "2.5.3", - "home-or-tmp": "2.0.0", - "lodash": "4.17.4", - "mkdirp": "0.5.1", - "source-map-support": "0.4.18" + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" } }, "babel-runtime": { @@ -391,21 +193,20 @@ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "core-js": "2.5.3", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-template": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.4" + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" } }, "babel-traverse": { @@ -413,15 +214,15 @@ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.2", - "lodash": "4.17.4" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" } }, "babel-types": { @@ -429,10 +230,10 @@ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.4", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, "babylon": { @@ -440,105 +241,63 @@ "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" }, + "bail": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.3.tgz", + "integrity": "sha512-1X8CnjFVQ+a+KW36uBNMTU5s8+v5FzeqrP7hTG5aTb4aPreSbZJlhwPon9VKMuEVgV++JM+SQrALY3kr7eswdg==" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "requires": { - "cache-base": "1.0.1", - "class-utils": "0.3.5", - "component-emitter": "1.2.1", - "define-property": "1.0.0", - "isobject": "3.0.1", - "mixin-deep": "1.3.0", - "pascalcase": "0.1.1" + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" } }, - "beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", - "dev": true - }, "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true, + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "braces": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.0.tgz", - "integrity": "sha512-P4O8UQRdGiMLWSizsApmXVQDBS6KCt7dSexgLKBmH5Hr1CZq7vsnscFh8oR1sP1ab1Zj0uCHCEzZeV6SfUf3rA==", - "dev": true, - "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "define-property": "1.0.0", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.2", - "snapdragon": "0.8.1", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.1" - } - }, "browser-stdout": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", "dev": true }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", "requires": { - "collection-visit": "1.0.0", - "component-emitter": "1.2.1", - "get-value": "2.0.6", - "has-value": "1.0.0", - "isobject": "3.0.1", - "set-value": "2.0.0", - "to-object-path": "0.3.0", - "union-value": "1.0.0", - "unset-value": "1.0.0" + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" } }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, - "requires": { - "callsites": "0.2.0" - } + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" + }, + "ccount": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.3.tgz", + "integrity": "sha512-Jt9tIBkRc9POUof7QA/VwWd+58fKkEEfI+/t1/eOlxKM7ZhrczNzMFefge7Ai+39y1pR/pP6cI19guHy3FSLmw==" }, "chai": { "version": "4.1.2", @@ -546,12 +305,12 @@ "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", "dev": true, "requires": { - "assertion-error": "1.0.2", - "check-error": "1.0.2", - "deep-eql": "3.0.1", - "get-func-name": "2.0.0", - "pathval": "1.1.0", - "type-detect": "4.0.5" + "assertion-error": "^1.0.1", + "check-error": "^1.0.1", + "deep-eql": "^3.0.0", + "get-func-name": "^2.0.0", + "pathval": "^1.0.0", + "type-detect": "^4.0.0" } }, "chalk": { @@ -559,18 +318,32 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", - "dev": true + "character-entities": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.2.tgz", + "integrity": "sha512-sMoHX6/nBiy3KKfC78dnEalnpn0Az0oSNvqUWYTtYrhRI5iUIYsROU48G+E+kMFQzqXaJ8kHJZ85n7y6/PHgwQ==" + }, + "character-entities-html4": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.2.tgz", + "integrity": "sha512-sIrXwyna2+5b0eB9W149izTPJk/KkJTg6mEzDGibwBUkyH1SbDa+nf515Ppdi3MaH35lW0JFJDWeq9Luzes1Iw==" + }, + "character-entities-legacy": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.2.tgz", + "integrity": "sha512-9NB2VbXtXYWdXzqrvAHykE/f0QJxzaKIpZ5QzNZrrgQ7Iyxr2vnfS8fCBNVW9nUEZE0lo57nxKRqnzY/dKrwlA==" + }, + "character-reference-invalid": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.2.tgz", + "integrity": "sha512-7I/xceXfKyUJmSAn/jw8ve/9DyOP7XxufNYLI9Px7CmsKgEUaZLUTax6nZxGQtaoiZCjpu6cHPj20xC/vqRReQ==" }, "check-error": { "version": "1.0.2", @@ -578,154 +351,33 @@ "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", "dev": true }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true - }, - "class-utils": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.5.tgz", - "integrity": "sha1-F+eTEDdQ+WJ7IXbqNM/RtWWQPIA=", - "dev": true, - "requires": { - "arr-union": "3.1.0", - "define-property": "0.2.5", - "isobject": "3.0.1", - "lazy-cache": "2.0.2", - "static-extend": "0.1.2" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, - "clone": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz", - "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=", - "dev": true - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true + "chownr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", + "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=" }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "1.0.0", - "object-visit": "1.0.1" - } + "collapse-white-space": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.4.tgz", + "integrity": "sha512-YfQ1tAUZm561vpYD+5eyWN8+UsceQbSrqqlc/6zDY2gtAE+uZLSdkkovhnGpmCThsvKBFakq4EdY/FF93E8XIw==" }, "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", "requires": { - "color-name": "1.1.3" + "color-name": "1.1.1" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" }, "commander": { "version": "2.11.0", @@ -733,98 +385,30 @@ "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", "dev": true }, - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concat-stream": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", - "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "typedarray": "0.0.6" - } + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "convert-source-map": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", - "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", - "dev": true - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true + "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=" }, "core-js": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", - "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.3.0" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", - "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", - "dev": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - } - } - } - }, - "damerau-levenshtein": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz", - "integrity": "sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ=", - "dev": true - }, - "dargs": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-5.1.0.tgz", - "integrity": "sha1-7H6lDHhWTNNsnV7Bj2Yyn63ieCk=", - "dev": true - }, - "dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "debug": { "version": "2.6.9", @@ -834,11 +418,13 @@ "ms": "2.0.0" } }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "^1.0.0" + } }, "deep-eql": { "version": "3.0.1", @@ -846,2042 +432,355 @@ "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, "requires": { - "type-detect": "4.0.5" + "type-detect": "^4.0.0" } }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "dev": true, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", "requires": { - "clone": "1.0.3" + "repeating": "^2.0.0" } }, - "define-properties": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", - "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", - "dev": true, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, + "diff": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", + "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "requires": { - "foreach": "2.0.5", - "object-keys": "1.0.11" + "once": "^1.4.0" } }, - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "1.0.2" - } - }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true, - "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.0", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" - } - }, - "deprecated": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz", - "integrity": "sha1-+cmvVGSvoeepcUWKi97yqpTVuxk=", - "dev": true - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true - }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true, - "requires": { - "repeating": "2.0.1" - } - }, - "diff": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", - "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", - "dev": true - }, - "doctrine": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.2.tgz", - "integrity": "sha512-y0tm5Pq6ywp3qSTZ1vPgVdAnbDEoeoc5wlOHXoY1c4Wug/a7JvqHIl7BTvwodaHmejWkK/9dSb3sCYfyo/om8A==", - "dev": true, - "requires": { - "esutils": "2.0.2" - } - }, - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", - "dev": true, - "requires": { - "readable-stream": "1.1.14" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, - "emoji-regex": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz", - "integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==", - "dev": true - }, - "encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "dev": true, - "requires": { - "iconv-lite": "0.4.19" - } - }, - "end-of-stream": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", - "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", - "dev": true, - "requires": { - "once": "1.3.3" - }, - "dependencies": { - "once": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - } - } - }, - "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "dev": true, - "requires": { - "is-arrayish": "0.2.1" - } - }, - "es-abstract": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.10.0.tgz", - "integrity": "sha512-/uh/DhdqIOSkAWifU+8nG78vlQxdLckUdI/sPgy0VhuXi2qJ7T8czBmqIYtLQVpCIFYafChnsRsB5pyb1JdmCQ==", - "dev": true, - "requires": { - "es-to-primitive": "1.1.1", - "function-bind": "1.1.1", - "has": "1.0.1", - "is-callable": "1.1.3", - "is-regex": "1.0.4" - } - }, - "es-to-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", - "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", - "dev": true, - "requires": { - "is-callable": "1.1.3", - "is-date-object": "1.0.1", - "is-symbol": "1.0.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "eslint": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.14.0.tgz", - "integrity": "sha512-Ul6CSGRjKscEyg0X/EeNs7o2XdnbTEOD1OM8cTjmx85RPcBJQrEhZLevhuJZNAE/vS2iVl5Uhgiqf3h5uLMCJQ==", - "dev": true, - "requires": { - "ajv": "5.5.2", - "babel-code-frame": "6.26.0", - "chalk": "2.3.0", - "concat-stream": "1.6.0", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.0.2", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.2", - "esquery": "1.0.0", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.2", - "globals": "11.1.0", - "ignore": "3.3.7", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.0.1", - "js-yaml": "3.10.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.4", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.0", - "require-uncached": "1.0.3", - "semver": "5.4.1", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", - "table": "4.0.2", - "text-table": "0.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "dev": true, - "requires": { - "color-convert": "1.9.1" - } - }, - "chalk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", - "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", - "dev": true, - "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" - } - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "globals": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.1.0.tgz", - "integrity": "sha512-uEuWt9mqTlPDwSqi+sHjD4nWU/1N+q0fiWI9T1mZpD2UENqX20CFD5T/ziLZvztPaBKl7ZylUi1q6Qfm7E2CiQ==", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "3.0.0" - } - }, - "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "dev": true, - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "eslint-config-airbnb": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-16.1.0.tgz", - "integrity": "sha512-zLyOhVWhzB/jwbz7IPSbkUuj7X2ox4PHXTcZkEmDqTvd0baJmJyuxlFPDlZOE/Y5bC+HQRaEkT3FoHo9wIdRiw==", - "requires": { - "eslint-config-airbnb-base": "12.1.0" - } - }, - "eslint-config-airbnb-base": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", - "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", - "requires": { - "eslint-restricted-globals": "0.1.1" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.1.tgz", - "integrity": "sha512-yUtXS15gIcij68NmXmP9Ni77AQuCN0itXbCc/jWd8C6/yKZaSNXicpC8cgvjnxVdmfsosIXrjpzFq7GcDryb6A==", - "dev": true, - "requires": { - "debug": "2.6.9", - "resolve": "1.5.0" - } - }, - "eslint-module-utils": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz", - "integrity": "sha512-jDI/X5l/6D1rRD/3T43q8Qgbls2nq5km5KSqiwlyUbGo5+04fXhMKdCPhjwbqAa6HXWaMxj8Q4hQDIh7IadJQw==", - "dev": true, - "requires": { - "debug": "2.6.9", - "pkg-dir": "1.0.0" - } - }, - "eslint-plugin-import": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.8.0.tgz", - "integrity": "sha512-Rf7dfKJxZ16QuTgVv1OYNxkZcsu/hULFnC+e+w0Gzi6jMC3guQoWQgxYxc54IDRinlb6/0v5z/PxxIKmVctN+g==", - "dev": true, - "requires": { - "builtin-modules": "1.1.1", - "contains-path": "0.1.0", - "debug": "2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "0.3.1", - "eslint-module-utils": "2.1.1", - "has": "1.0.1", - "lodash.cond": "4.5.2", - "minimatch": "3.0.4", - "read-pkg-up": "2.0.0" - }, - "dependencies": { - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" - } - } - } - }, - "eslint-plugin-jsx-a11y": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.0.3.tgz", - "integrity": "sha1-VFg9GuRCSDFi4EDhPMMYZUZRAOU=", - "dev": true, - "requires": { - "aria-query": "0.7.0", - "array-includes": "3.0.3", - "ast-types-flow": "0.0.7", - "axobject-query": "0.1.0", - "damerau-levenshtein": "1.0.4", - "emoji-regex": "6.5.1", - "jsx-ast-utils": "2.0.1" - } - }, - "eslint-plugin-react": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.5.1.tgz", - "integrity": "sha512-YGSjB9Qu6QbVTroUZi66pYky3DfoIPLdHQ/wmrBGyBRnwxQsBXAov9j2rpXt/55i8nyMv6IRWJv2s4d4YnduzQ==", - "dev": true, - "requires": { - "doctrine": "2.0.2", - "has": "1.0.1", - "jsx-ast-utils": "2.0.1", - "prop-types": "15.6.0" - } - }, - "eslint-restricted-globals": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", - "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=" - }, - "eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", - "dev": true, - "requires": { - "esrecurse": "4.2.0", - "estraverse": "4.2.0" - } - }, - "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", - "dev": true - }, - "espree": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz", - "integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==", - "dev": true, - "requires": { - "acorn": "5.3.0", - "acorn-jsx": "3.0.1" - } - }, - "esquery": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", - "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", - "dev": true, - "requires": { - "estraverse": "4.2.0" - } - }, - "esrecurse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", - "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", - "dev": true, - "requires": { - "estraverse": "4.2.0", - "object-assign": "4.1.1" - } - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "execa": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz", - "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", - "dev": true, - "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.0", - "snapdragon": "0.8.1", - "to-regex": "3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "1.0.1" - } - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "0.1.1" - } - }, - "external-editor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz", - "integrity": "sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA==", - "dev": true, - "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.19", - "tmp": "0.0.33" - } - }, - "extglob": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.3.tgz", - "integrity": "sha512-AyptZexgu7qppEPq59DtN/XJGZDrLcVxSHai+4hdgMMS9EpF4GBvygcWWApno8lL9qSjVpYt7Raao28qzJX1ww==", - "dev": true, - "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.0", - "snapdragon": "0.8.1", - "to-regex": "3.0.1" - } - }, - "fancy-log": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", - "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", - "dev": true, - "requires": { - "ansi-gray": "0.1.1", - "color-support": "1.1.3", - "time-stamp": "1.1.0" - } - }, - "fast-deep-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", - "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fbjs": { - "version": "0.8.16", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", - "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", - "dev": true, - "requires": { - "core-js": "1.2.7", - "isomorphic-fetch": "2.2.1", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "promise": "7.3.1", - "setimmediate": "1.0.5", - "ua-parser-js": "0.7.17" - }, - "dependencies": { - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", - "dev": true - } - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "1.0.5" - } - }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "dev": true, - "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" - } - }, - "find-index": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", - "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", - "dev": true - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, - "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", - "dev": true, - "requires": { - "detect-file": "1.0.0", - "is-glob": "3.1.0", - "micromatch": "3.1.4", - "resolve-dir": "1.0.1" - }, - "dependencies": { - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "2.1.1" - } - } - } - }, - "fined": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.0.tgz", - "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", - "dev": true, - "requires": { - "expand-tilde": "2.0.2", - "is-plain-object": "2.0.4", - "object.defaults": "1.1.0", - "object.pick": "1.3.0", - "parse-filepath": "1.0.2" - } - }, - "first-chunk-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", - "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=", - "dev": true - }, - "flagged-respawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.0.tgz", - "integrity": "sha1-Tnmumy6zi/hrO7Vr8+ClaqX8q9c=", - "dev": true - }, - "flat-cache": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", - "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", - "dev": true, - "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "1.0.2" - } - }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "0.2.2" - } - }, - "fs-extra": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz", - "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==", - "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "4.0.0", - "universalify": "0.1.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gaze": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz", - "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", - "dev": true, - "requires": { - "globule": "0.1.0" - } - }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "glob-stream": { - "version": "3.1.18", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", - "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", - "dev": true, - "requires": { - "glob": "4.5.3", - "glob2base": "0.0.12", - "minimatch": "2.0.10", - "ordered-read-streams": "0.1.0", - "through2": "0.6.5", - "unique-stream": "1.0.0" - }, - "dependencies": { - "glob": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", - "dev": true, - "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "2.0.10", - "once": "1.4.0" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", - "dev": true, - "requires": { - "brace-expansion": "1.1.8" - } - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": "1.0.34", - "xtend": "4.0.1" - } - } - } - }, - "glob-watcher": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", - "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", - "dev": true, - "requires": { - "gaze": "0.5.2" - } - }, - "glob2base": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", - "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", - "dev": true, - "requires": { - "find-index": "0.1.1" - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "requires": { - "global-prefix": "1.0.2", - "is-windows": "1.0.1", - "resolve-dir": "1.0.1" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "requires": { - "expand-tilde": "2.0.2", - "homedir-polyfill": "1.0.1", - "ini": "1.3.5", - "is-windows": "1.0.1", - "which": "1.3.0" - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" - }, - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dev": true, - "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "globule": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz", - "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", - "dev": true, - "requires": { - "glob": "3.1.21", - "lodash": "1.0.2", - "minimatch": "0.2.14" - }, - "dependencies": { - "glob": { - "version": "3.1.21", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", - "dev": true, - "requires": { - "graceful-fs": "1.2.3", - "inherits": "1.0.2", - "minimatch": "0.2.14" - } - }, - "graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "dev": true - }, - "inherits": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", - "dev": true - }, - "lodash": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", - "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", - "dev": true - }, - "minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "dev": true, - "requires": { - "lru-cache": "2.7.3", - "sigmund": "1.0.1" - } - } - } - }, - "glogg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz", - "integrity": "sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U=", - "dev": true, - "requires": { - "sparkles": "1.0.0" - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "growl": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", - "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", - "dev": true - }, - "gulp": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", - "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", - "dev": true, - "requires": { - "archy": "1.0.0", - "chalk": "1.1.3", - "deprecated": "0.0.1", - "gulp-util": "3.0.8", - "interpret": "1.1.0", - "liftoff": "2.5.0", - "minimist": "1.2.0", - "orchestrator": "0.3.8", - "pretty-hrtime": "1.0.3", - "semver": "4.3.6", - "tildify": "1.2.0", - "v8flags": "2.1.1", - "vinyl-fs": "0.3.14" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", - "dev": true - } - } - }, - "gulp-eslint": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-4.0.0.tgz", - "integrity": "sha512-+qsePo04v1O3JshpNvww9+bOgZEJ6Cc2/w3mEktfKz0NL0zsh1SWzjyIL2FIM2zzy6IYQYv+j8REZORF8dKX4g==", - "dev": true, - "requires": { - "eslint": "4.14.0", - "gulp-util": "3.0.8" - } - }, - "gulp-mocha": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/gulp-mocha/-/gulp-mocha-5.0.0.tgz", - "integrity": "sha512-NIjXZLqqcw9DXIEBcfm0sP1AUDlUJJeaK9EGCH2s6lSwo5NK/cEat0Vm7XelOkxZnWl0O5Za+aM6E4jyxWxTlw==", - "dev": true, - "requires": { - "dargs": "5.1.0", - "execa": "0.8.0", - "mocha": "4.1.0", - "npm-run-path": "2.0.2", - "plugin-error": "0.1.2", - "through2": "2.0.3" - } - }, - "gulp-util": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", - "dev": true, - "requires": { - "array-differ": "1.0.0", - "array-uniq": "1.0.3", - "beeper": "1.1.1", - "chalk": "1.1.3", - "dateformat": "2.2.0", - "fancy-log": "1.3.2", - "gulplog": "1.0.0", - "has-gulplog": "0.1.0", - "lodash._reescape": "3.0.0", - "lodash._reevaluate": "3.0.0", - "lodash._reinterpolate": "3.0.0", - "lodash.template": "3.6.2", - "minimist": "1.2.0", - "multipipe": "0.1.2", - "object-assign": "3.0.0", - "replace-ext": "0.0.1", - "through2": "2.0.3", - "vinyl": "0.5.3" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", - "dev": true - }, - "vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", - "dev": true, - "requires": { - "clone": "1.0.3", - "clone-stats": "0.0.1", - "replace-ext": "0.0.1" - } - } - } - }, - "gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", - "dev": true, - "requires": { - "glogg": "1.0.0" - } - }, - "has": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", - "dev": true, - "requires": { - "function-bind": "1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "2.1.1" - } - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "has-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", - "dev": true, - "requires": { - "sparkles": "1.0.0" - } - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "2.0.6", - "has-values": "1.0.0", - "isobject": "3.0.1" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", - "dev": true - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "dev": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "homedir-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", - "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", - "dev": true, - "requires": { - "parse-passwd": "1.0.0" - } - }, - "hosted-git-info": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", - "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", - "dev": true - }, - "ignore": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", - "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true - }, - "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", - "dev": true, - "requires": { - "ansi-escapes": "3.0.0", - "chalk": "2.3.0", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.1.0", - "figures": "2.0.0", - "lodash": "4.17.4", - "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "dev": true, - "requires": { - "color-convert": "1.9.1" - } - }, - "chalk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", - "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", - "dev": true, - "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "3.0.0" - } - }, - "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "dev": true, - "requires": { - "has-flag": "2.0.0" - } - } - } + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, - "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", - "dev": true + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, - "invariant": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", - "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", - "requires": { - "loose-envify": "1.3.1" - } + "expand-template": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.1.tgz", + "integrity": "sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg==" }, - "is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", - "dev": true, - "requires": { - "is-relative": "1.0.0", - "is-windows": "1.0.1" - } + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, - "is-accessor-descriptor": { + "fs-constants": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, + "fs-extra": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz", + "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==", "requires": { - "builtin-modules": "1.1.1" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, - "is-callable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", - "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", - "dev": true - }, - "is-data-descriptor": { + "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "6.0.2" - } - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "requires": { - "number-is-nan": "1.0.1" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" } }, - "is-fullwidth-code-point": { + "get-func-name": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-odd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-1.0.0.tgz", - "integrity": "sha1-O4qTLrAos3dcObsJ6RdnrM22kIg=", - "dev": true, - "requires": { - "is-number": "3.0.0" - } - }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", - "dev": true - }, - "is-path-in-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", - "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", - "dev": true, - "requires": { - "is-path-inside": "1.0.1" - } - }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dev": true, - "requires": { - "path-is-inside": "1.0.2" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "3.0.1" - } - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "requires": { - "has": "1.0.1" - } - }, - "is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", - "dev": true, - "requires": { - "is-unc-path": "1.0.0" - } - }, - "is-resolvable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.1.tgz", - "integrity": "sha512-y5CXYbzvB3jTnWAZH1Nl7ykUWb6T3BcTs56HUruwBf8MhF56n1HWqhDWnVFo8GHrUPDgvUUNVhrc2U8W7iqz5g==", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "dev": true }, - "is-symbol": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", - "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", - "dev": true + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" }, - "is-unc-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "unc-path-regex": "0.1.2" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" }, - "is-windows": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.1.tgz", - "integrity": "sha1-MQ23D3QtJZoWo2kgK1GvhCMzENk=", - "dev": true + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "growl": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", + "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", "dev": true }, - "isexe": { + "has-ansi": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "isomorphic-fetch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", - "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", - "dev": true, - "requires": { - "node-fetch": "1.7.3", - "whatwg-fetch": "2.0.3" - } - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - }, - "js-yaml": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", - "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", - "dev": true, + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { - "argparse": "1.0.9", - "esprima": "4.0.0" - }, - "dependencies": { - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", - "dev": true - } + "ansi-regex": "^2.0.0" } }, - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "4.1.11" - } + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, - "jsx-ast-utils": { + "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz", - "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=", - "dev": true, - "requires": { - "array-includes": "3.0.3" - } + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", "dev": true }, - "lazy-cache": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", - "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", - "dev": true, - "requires": { - "set-getter": "0.1.0" - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" - } - }, - "liftoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", - "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", - "dev": true, - "requires": { - "extend": "3.0.1", - "findup-sync": "2.0.0", - "fined": "1.1.0", - "flagged-respawn": "1.0.0", - "is-plain-object": "2.0.4", - "object.map": "1.0.1", - "rechoir": "0.6.2", - "resolve": "1.5.0" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" - } - }, - "locate-path": { + "home-or-tmp": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } - }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" - }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true - }, - "lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", - "dev": true - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true - }, - "lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", - "dev": true - }, - "lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - }, - "lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", - "dev": true - }, - "lodash.cond": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", - "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=", - "dev": true + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" + } }, - "lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "lodash._root": "3.0.1" + "once": "^1.3.0", + "wrappy": "1" } }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "requires": { - "lodash._getnative": "3.9.1", - "lodash.isarguments": "3.1.0", - "lodash.isarray": "3.0.4" + "loose-envify": "^1.0.0" } }, - "lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", - "dev": true + "is-alphabetical": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.2.tgz", + "integrity": "sha512-V0xN4BYezDHcBSKb1QHUFMlR4as/XEuCZBzMJUU4n7+Cbt33SmUnSol+pnXFvLxSHNq2CemUXNdaXV6Flg7+xg==" }, - "lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", - "dev": true, + "is-alphanumeric": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz", + "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=" + }, + "is-alphanumerical": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.2.tgz", + "integrity": "sha512-pyfU/0kHdISIgslFfZN9nfY1Gk3MquQgUm1mJTjdkEPpkAKNWuBTSqFwewOpR7N351VkErCiyV71zX7mlQQqsg==", "requires": { - "lodash._basecopy": "3.0.1", - "lodash._basetostring": "3.0.1", - "lodash._basevalues": "3.0.0", - "lodash._isiterateecall": "3.0.9", - "lodash._reinterpolate": "3.0.0", - "lodash.escape": "3.2.0", - "lodash.keys": "3.1.2", - "lodash.restparam": "3.6.1", - "lodash.templatesettings": "3.1.1" + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" } }, - "lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", - "dev": true, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-decimal": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.2.tgz", + "integrity": "sha512-TRzl7mOCchnhchN+f3ICUCzYvL9ul7R+TYOsZ8xia++knyZAJfv/uA1FvQXsAnYIl1T3B2X5E/J7Wb1QXiIBXg==" + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "requires": { - "lodash._reinterpolate": "3.0.0", - "lodash.escape": "3.2.0" + "number-is-nan": "^1.0.0" } }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { - "js-tokens": "3.0.2" + "number-is-nan": "^1.0.0" } }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true + "is-hexadecimal": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.2.tgz", + "integrity": "sha512-but/G3sapV3MNyqiDBLrOi4x8uCIw0RY3o/Vb5GT0sMFHrVV7731wFSVy41T5FO1og7G0gXLJh0MkgPRouko/A==" + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + }, + "is-whitespace-character": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.2.tgz", + "integrity": "sha512-SzM+T5GKUCtLhlHFKt2SDAX2RFzfS6joT91F2/WSi9LxgFdsnhfPK/UIA+JhRR2xuyLdrCys2PiFDrtn1fU5hQ==" + }, + "is-word-character": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.2.tgz", + "integrity": "sha512-T3FlsX8rCHAH8e7RE7PfOPZVFQlcV3XRF9eOOBQ1uf70OxO7CjjSOjeImMPCADBdYWcStAbVbYvJ1m2D3tb+EA==" }, - "make-iterator": { + "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.0.tgz", - "integrity": "sha1-V7713IXSOSO6I3ZzJNjo+PPZaUs=", - "dev": true, + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } + "graceful-fs": "^4.1.6" } }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, + "longest-streak": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.2.tgz", + "integrity": "sha512-TmYTeEYxiAmSVdpbnQDXGtvYOIRsCMg89CVZzwzc2o7GFL1CjoiRPjH5ec0NFAVlAx3fVof9dX/t6KKRAo2OWA==" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "requires": { - "object-visit": "1.0.1" + "js-tokens": "^3.0.0 || ^4.0.0" } }, - "micromatch": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.4.tgz", - "integrity": "sha512-kFRtviKYoAJT+t7HggMl0tBFGNAKLw/S7N+CO9qfEQyisob1Oy4pao+geRbkyeEd+V9aOkvZ4mhuyPvI/q9Sfg==", - "dev": true, + "markdown-escapes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.2.tgz", + "integrity": "sha512-lbRZ2mE3Q9RtLjxZBZ9+IMl68DKIXaVAhwvwn9pmjnPLS0h/6kyBMgNhqi1xFJ/2yv6cSyv0jbiZavZv93JkkA==" + }, + "markdown-table": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.2.tgz", + "integrity": "sha512-NcWuJFHDA8V3wkDgR/j4+gZx+YQwstPgfQDV8ndUeWWzta3dnDTBxpVzqS9lkmJAuV5YX35lmyojl6HO5JXAgw==" + }, + "mdast-util-compact": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.2.tgz", + "integrity": "sha512-d2WS98JSDVbpSsBfVvD9TaDMlqPRz7ohM/11G0rp5jOBb5q96RJ6YLszQ/09AAixyzh23FeIpCGqfaamEADtWg==", "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.0", - "define-property": "1.0.0", - "extend-shallow": "2.0.1", - "extglob": "2.0.3", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.6", - "object.pick": "1.3.0", - "regex-not": "1.0.0", - "snapdragon": "0.8.1", - "to-regex": "3.0.1" + "unist-util-visit": "^1.1.0" } }, - "mimic-fn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", - "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", - "dev": true + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { - "brace-expansion": "1.1.8" + "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mixin-deep": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.0.tgz", - "integrity": "sha512-dgaCvoh6i1nosAUBKb0l0pfJ78K8+S9fluyIR2YvAeUD/QuMahnFnF3xYty5eYXMjhGSsB0DsW6A0uAZyetoAg==", - "dev": true, - "requires": { - "for-in": "1.0.2", - "is-extendable": "1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "2.0.4" - } - } - } + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, "requires": { "minimist": "0.0.8" } @@ -2913,51 +812,57 @@ "ms": "2.0.0" } }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, "supports-color": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", "dev": true, "requires": { - "has-flag": "2.0.0" + "has-flag": "^2.0.0" } } } }, "mr-doc-utils": { - "version": "git+https://github.com/mr-doc/mr-doc-utils.git#1f4966dc55a647b2b21ea956cbc18396e8636661", + "version": "github:iwatakeshi/mr-doc-utils#d56b77b857f9cdb08a42686a871391f6f8408350", + "from": "github:iwatakeshi/mr-doc-utils", "requires": { - "chalk": "2.3.0", - "eslint-config-airbnb": "16.1.0", - "fs-extra": "5.0.0", - "lodash": "4.17.4", - "sparkles": "1.0.0" + "chalk": "^2.4.1", + "fs-extra": "^5.0.0", + "lodash": "^4.17.10", + "sparkles": "^1.0.1" }, "dependencies": { "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "color-convert": "1.9.1" + "color-convert": "^1.9.0" } }, "chalk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", - "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "2.0.0" + "has-flag": "^3.0.0" } } } @@ -2967,387 +872,80 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", - "dev": true, - "requires": { - "duplexer2": "0.0.2" - } - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "nanomatch": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.6.tgz", - "integrity": "sha512-WJ6XTCbvWXUFPbi/bDwKcYkCeOGUHzaJj72KbuPqGn78Ba/F5Vu26Zlo6SuMQbCIst1RGKL1zfWBCOGAlbRLAg==", - "dev": true, - "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "define-property": "1.0.0", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "is-odd": "1.0.0", - "kind-of": "5.1.0", - "object.pick": "1.3.0", - "regex-not": "1.0.0", - "snapdragon": "0.8.1", - "to-regex": "3.0.1" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "natives": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.1.tgz", - "integrity": "sha512-8eRaxn8u/4wN8tGkhlc2cgwwvOLMLUMUn4IYTexMgWd+LyUDfeXVkk2ygQR0hvIHbJQXgHujia3ieUUDwNGkEA==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true + "nan": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" }, - "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "dev": true, + "node-abi": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.3.tgz", + "integrity": "sha512-b656V5C0628gOOA2kwcpNA/bxdlqYF9FvxJ+qqVX0ctdXNVZpS8J6xEUYir3WAKc7U0BH/NRlSpNbGsy+azjeg==", "requires": { - "encoding": "0.1.12", - "is-stream": "1.1.0" + "semver": "^5.4.1" } }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, - "requires": { - "hosted-git-info": "2.5.0", - "is-builtin-module": "1.0.0", - "semver": "5.4.1", - "validate-npm-package-license": "3.0.1" - } + "noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "requires": { - "path-key": "2.0.1" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "0.1.1", - "define-property": "0.2.5", - "kind-of": "3.2.2" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "object-keys": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", - "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "3.0.1" - } - }, - "object.defaults": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", - "dev": true, - "requires": { - "array-each": "1.0.1", - "array-slice": "1.1.0", - "for-own": "1.0.0", - "isobject": "3.0.1" - } - }, - "object.map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", - "dev": true, - "requires": { - "for-own": "1.0.0", - "make-iterator": "1.0.0" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "3.0.1" - } + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "1.1.0" - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" - } - }, - "orchestrator": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.8.tgz", - "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", - "dev": true, "requires": { - "end-of-stream": "0.1.5", - "sequencify": "0.0.7", - "stream-consume": "0.1.0" + "wrappy": "1" } }, - "ordered-read-streams": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", - "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", - "dev": true - }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", - "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", - "dev": true - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "1.1.0" - } - }, - "parse-filepath": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", - "dev": true, - "requires": { - "is-absolute": "1.0.0", - "map-cache": "0.2.2", - "path-root": "0.1.1" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "1.3.1" - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, + "parse-entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.1.2.tgz", + "integrity": "sha512-5N9lmQ7tmxfXf+hO3X6KRG6w7uYO/HL9fHalSySTdyn63C3WNvTM/1R8tn1u1larNcEbo3Slcy2bsVDQqvEpUg==", "requires": { - "pinkie-promise": "2.0.1" + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" } }, "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", - "dev": true - }, - "path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", - "dev": true, - "requires": { - "path-root-regex": "0.1.2" - } - }, - "path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", - "dev": true - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "2.3.0" - } + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "pathval": { "version": "1.1.0", @@ -3355,210 +953,84 @@ "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", "dev": true }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "2.0.4" - } - }, - "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", - "dev": true, - "requires": { - "find-up": "1.1.2" - } - }, - "plugin-error": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", - "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", - "dev": true, - "requires": { - "ansi-cyan": "0.1.1", - "ansi-red": "0.1.1", - "arr-diff": "1.1.0", - "arr-union": "2.1.0", - "extend-shallow": "1.1.4" + "prebuild-install": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.0.0.tgz", + "integrity": "sha512-AvcPLFqNz/hDd6o7qLj8i9xB479P9jSjA/p6m4927CRfY3tsmPfyFmD7RKXtdp6I2d1BAIVBgJoj5mxRJDZL4w==", + "requires": { + "detect-libc": "^1.0.3", + "expand-template": "^1.0.2", + "github-from-package": "0.0.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "node-abi": "^2.2.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "os-homedir": "^1.0.1", + "pump": "^2.0.1", + "rc": "^1.2.7", + "simple-get": "^2.7.0", + "tar-fs": "^1.13.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" }, "dependencies": { - "arr-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", - "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", - "dev": true, - "requires": { - "arr-flatten": "1.1.0", - "array-slice": "0.2.3" - } - }, - "arr-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", - "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=", - "dev": true - }, - "array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", - "dev": true - }, - "extend-shallow": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", - "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", - "dev": true, - "requires": { - "kind-of": "1.1.0" - } - }, - "kind-of": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", - "dev": true + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" } } }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", - "dev": true - }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" }, "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "progress": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", - "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", - "dev": true - }, - "promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "dev": true, - "requires": { - "asap": "2.0.6" - } + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, - "prop-types": { - "version": "15.6.0", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.0.tgz", - "integrity": "sha1-zq8IMCL8RrSjX2nhPvda7Q1jmFY=", - "dev": true, - "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "2.0.0" - } + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" } } }, "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "resolve": "1.5.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "regenerator-runtime": { @@ -3566,542 +1038,167 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, - "regex-not": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.0.tgz", - "integrity": "sha1-Qvg+OXcWIt+CawKvF2Ul1qXxV/k=", - "dev": true, + "remark": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/remark/-/remark-9.0.0.tgz", + "integrity": "sha512-amw8rGdD5lHbMEakiEsllmkdBP+/KpjW/PRK6NSGPZKCQowh0BT4IWXDAkRMyG3SB9dKPXWMviFjNusXzXNn3A==", "requires": { - "extend-shallow": "2.0.1" + "remark-parse": "^5.0.0", + "remark-stringify": "^5.0.0", + "unified": "^6.0.0" } }, - "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", - "dev": true + "remark-parse": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-5.0.0.tgz", + "integrity": "sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==", + "requires": { + "collapse-white-space": "^1.0.2", + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "is-word-character": "^1.0.0", + "markdown-escapes": "^1.0.0", + "parse-entities": "^1.1.0", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "trim": "0.0.1", + "trim-trailing-lines": "^1.0.0", + "unherit": "^1.0.4", + "unist-util-remove-position": "^1.0.0", + "vfile-location": "^2.0.0", + "xtend": "^4.0.1" + } + }, + "remark-stringify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-5.0.0.tgz", + "integrity": "sha512-Ws5MdA69ftqQ/yhRF9XhVV29mhxbfGhbz0Rx5bQH+oJcNhhSM6nCu1EpLod+DjrFGrU0BMPs+czVmJZU7xiS7w==", + "requires": { + "ccount": "^1.0.0", + "is-alphanumeric": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "longest-streak": "^2.0.1", + "markdown-escapes": "^1.0.0", + "markdown-table": "^1.1.0", + "mdast-util-compact": "^1.0.0", + "parse-entities": "^1.0.2", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "stringify-entities": "^1.0.1", + "unherit": "^1.0.4", + "xtend": "^4.0.1" + } }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" }, "repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, "requires": { - "is-finite": "1.0.2" + "is-finite": "^1.0.0" } }, "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true - }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" - } - }, - "resolve": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", - "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", - "dev": true, - "requires": { - "path-parse": "1.0.5" - } - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "requires": { - "expand-tilde": "2.0.2", - "global-modules": "1.0.0" - } - }, - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" - } - }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dev": true, - "requires": { - "glob": "7.1.2" - } - }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, - "requires": { - "is-promise": "2.1.0" - } - }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", - "dev": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", - "dev": true, - "requires": { - "rx-lite": "4.0.8" - } + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=" }, "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "semver": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", - "dev": true - }, - "sequencify": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz", - "integrity": "sha1-kM/xnQLgcCf9dn9erT57ldHnOAw=", - "dev": true + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==" }, - "set-getter": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz", - "integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=", - "dev": true, - "requires": { - "to-object-path": "0.3.0" - } - }, - "set-value": { + "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", - "dev": true, - "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "split-string": "3.1.0" - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, - "slice-ansi": { + "simple-concat": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "2.0.0" - } - }, - "snapdragon": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.1.tgz", - "integrity": "sha1-4StUh/re0+PeoKyR6UAL91tAE3A=", - "dev": true, - "requires": { - "base": "0.11.2", - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "map-cache": "0.2.2", - "source-map": "0.5.7", - "source-map-resolve": "0.5.1", - "use": "2.0.2" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", + "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, + "simple-get": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", + "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", "requires": { - "define-property": "1.0.0", - "isobject": "3.0.1", - "snapdragon-util": "3.0.1" + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" } }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", - "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", - "dev": true, - "requires": { - "atob": "2.0.3", - "decode-uri-component": "0.2.0", - "resolve-url": "0.2.1", - "source-map-url": "0.4.0", - "urix": "0.1.0" - } - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "0.5.7" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "sparkles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz", - "integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM=" - }, - "spdx-correct": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", - "dev": true, - "requires": { - "spdx-license-ids": "1.2.2" - } - }, - "spdx-expression-parse": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", - "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", - "dev": true - }, - "spdx-license-ids": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", - "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "3.0.2" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "2.0.4" - } - } - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "requires": { - "define-property": "0.2.5", - "object-copy": "0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "source-map": "^0.5.6" } }, - "stream-consume": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz", - "integrity": "sha1-pB6tGm1ggc63n2WwYZAbbY89HQ8=", - "dev": true + "sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==" + }, + "state-toggle": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.1.tgz", + "integrity": "sha512-Qe8QntFrrpWTnHwvwj2FZTgv+PKIsp0B9VxLzLLbSpPXWOgRgc5LVj/aTiSfK1RqIeF9jeC1UeOH8Q8y60A7og==" }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "3.0.0" - } - } + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "stringify-entities": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-1.3.2.tgz", + "integrity": "sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A==", "requires": { - "safe-buffer": "5.1.1" + "character-entities-html4": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-hexadecimal": "^1.0.0" } }, "strip-ansi": { @@ -4109,605 +1206,256 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" }, - "table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", - "dev": true, + "tar-fs": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", + "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", "requires": { - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "chalk": "2.3.0", - "lodash": "4.17.4", - "slice-ansi": "1.0.0", - "string-width": "2.1.1" + "chownr": "^1.0.1", + "mkdirp": "^0.5.1", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" }, "dependencies": { - "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "dev": true, - "requires": { - "color-convert": "1.9.1" - } - }, - "chalk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", - "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", - "dev": true, + "pump": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", + "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" - } - }, - "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "dev": true, - "requires": { - "has-flag": "2.0.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } } } }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, - "requires": { - "readable-stream": "2.3.3", - "xtend": "4.0.1" - } - }, - "tildify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", - "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", - "dev": true, + "tar-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.1.tgz", + "integrity": "sha512-IFLM5wp3QrJODQFPm6/to3LJZrONdBY/otxcvDIQzu217zKye6yVR3hhi9lAjrC2Z+m/j5oDxMPb1qcd8cIvpA==", "requires": { - "os-homedir": "1.0.2" + "bl": "^1.0.0", + "buffer-alloc": "^1.1.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.0", + "xtend": "^4.0.0" } }, - "time-stamp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", - "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "1.0.2" - } + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" }, "to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, + "tree-crawl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tree-crawl/-/tree-crawl-1.0.5.tgz", + "integrity": "sha512-iGxq6nMcZ2PCRQOHykbhM5nMBiErA9iVfWvfatKlfAZ4O4t/46BfrbZfTcoNM6H6o6TYHQvxHtPWEnvPqH7rDA==" + }, + "tree-sitter": { + "version": "0.13.8", + "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.13.8.tgz", + "integrity": "sha512-LfKtMRxRjYfVSnrkwAMfwO8MH493G05fnw8QHaiB6p2iSjP9RHOLnXP1VxR4FlhQqyYRIbdUx/VCBoyntzB5Pg==", "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } + "nan": "^2.10.0", + "prebuild-install": "^5.0.0" } }, - "to-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.1.tgz", - "integrity": "sha1-FTWL7kosg712N3uh3ASdDxiDeq4=", - "dev": true, + "tree-sitter-javascript": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/tree-sitter-javascript/-/tree-sitter-javascript-0.13.5.tgz", + "integrity": "sha512-80sUl2+kj0evGTueODpDmJksTNQbGtkG4EOxIygsjZ5Q6kFW/uBRHXHSlBtX5vkEIjljApZ8qse4C7cmG1CIFA==", "requires": { - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "regex-not": "1.0.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "nan": "^2.4.0" } }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, + "tree-sitter-typescript": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/tree-sitter-typescript/-/tree-sitter-typescript-0.13.3.tgz", + "integrity": "sha512-PF/yDQNtjOU0pDHdy4QqYB8yPgfEeZz7PsG+IwYYC6xt3XQBRKJDIGyPPSHSvSZFE2ln4GBnJ7/EDneiNXqrlA==", "requires": { - "is-number": "3.0.0", - "repeat-string": "1.6.1" + "nan": "^2.10.0" } }, + "trim": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", + "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=" + }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, + "trim-trailing-lines": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.1.tgz", + "integrity": "sha512-bWLv9BbWbbd7mlqqs2oQYnLD/U/ZqeJeJwbO0FG2zA1aTq+HTvxfHNKFa/HGCVyJpDiioUYaBhfiT6rgk+l4mg==" + }, + "trough": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.3.tgz", + "integrity": "sha512-fwkLWH+DimvA4YCy+/nvJd61nWQQ2liO/nF/RjkTpiOGi+zxZzVkhb1mvbHIIW4b/8nDsYI8uTmAlc0nNkRMOw==" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "prelude-ls": "1.1.2" + "safe-buffer": "^5.0.1" } }, "type-detect": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.5.tgz", - "integrity": "sha512-N9IvkQslUGYGC24RkJk1ba99foK6TkwC2FHAEBlQFBP0RxQZS8ZpJuAZcwiY/w9ZJHFQb1aOXBI60OdxhTrwEQ==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true + "unherit": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.1.tgz", + "integrity": "sha512-+XZuV691Cn4zHsK0vkKYwBEwB74T3IZIcxrgn2E4rKwTfFyI1zCh7X7grwh9Re08fdPlarIdyWgI8aVB3F5A5g==", + "requires": { + "inherits": "^2.0.1", + "xtend": "^4.0.1" + } }, - "ua-parser-js": { - "version": "0.7.17", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz", - "integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g==", - "dev": true + "unified": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-6.2.0.tgz", + "integrity": "sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==", + "requires": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^1.1.0", + "trough": "^1.0.0", + "vfile": "^2.0.0", + "x-is-string": "^0.1.0" + } }, - "unc-path-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", - "dev": true + "unist-util-is": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-2.1.2.tgz", + "integrity": "sha512-YkXBK/H9raAmG7KXck+UUpnKiNmUdB+aBGrknfQ4EreE1banuzrKABx3jP6Z5Z3fMSPMQQmeXBlKpCbMwBkxVw==" }, - "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", - "dev": true, + "unist-util-remove-position": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.2.tgz", + "integrity": "sha512-XxoNOBvq1WXRKXxgnSYbtCF76TJrRoe5++pD4cCBsssSiWSnPEktyFrFLE8LTk3JW5mt9hB0Sk5zn4x/JeWY7Q==", "requires": { - "arr-union": "3.1.0", - "get-value": "2.0.6", - "is-extendable": "0.1.1", - "set-value": "0.4.3" - }, - "dependencies": { - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "to-object-path": "0.3.0" - } - } + "unist-util-visit": "^1.1.0" } }, - "unique-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", - "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=", - "dev": true - }, - "universalify": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", - "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" + "unist-util-stringify-position": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz", + "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==" }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, + "unist-util-visit": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.0.tgz", + "integrity": "sha512-FiGu34ziNsZA3ZUteZxSFaczIjGmksfSgdKqBfOejrrfzyUy5b7YrlzT1Bcvi+djkYDituJDy2XB7tGTeBieKw==", "requires": { - "has-value": "0.3.1", - "isobject": "3.0.1" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "2.0.6", - "has-values": "0.1.4", - "isobject": "2.1.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } + "unist-util-visit-parents": "^2.0.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "use": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/use/-/use-2.0.2.tgz", - "integrity": "sha1-riig1y+TvyJCKhii43mZMRLeyOg=", - "dev": true, + "unist-util-visit-parents": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.0.1.tgz", + "integrity": "sha512-6B0UTiMfdWql4cQ03gDTCSns+64Zkfo2OCbK31Ov0uMizEz+CJeAp0cgZVb5Fhmcd7Bct2iRNywejT0orpbqUA==", "requires": { - "define-property": "0.2.5", - "isobject": "3.0.1", - "lazy-cache": "2.0.2" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "0.1.6" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "1.1.6" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "unist-util-is": "^2.1.2" } }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, - "v8flags": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", - "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", - "dev": true, + "vfile": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz", + "integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==", "requires": { - "user-home": "1.1.1" - }, - "dependencies": { - "user-home": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", - "dev": true - } + "is-buffer": "^1.1.4", + "replace-ext": "1.0.0", + "unist-util-stringify-position": "^1.0.0", + "vfile-message": "^1.0.0" } }, - "validate-npm-package-license": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", - "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", - "dev": true, - "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.4" - } + "vfile-location": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.3.tgz", + "integrity": "sha512-zM5/l4lfw1CBoPx3Jimxoc5RNDAHHpk6AM6LM0pTIkm5SUSsx8ZekZ0PVdf0WEZ7kjlhSt7ZlqbRL6Cd6dBs6A==" }, - "vinyl-fs": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz", - "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", - "dev": true, + "vfile-message": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.0.1.tgz", + "integrity": "sha512-vSGCkhNvJzO6VcWC6AlJW4NtYOVtS+RgCaqFIYUjoGIlHnFL+i0LbtYvonDWOMcB97uTPT4PRsyYY7REWC9vug==", "requires": { - "defaults": "1.0.3", - "glob-stream": "3.1.18", - "glob-watcher": "0.0.6", - "graceful-fs": "3.0.11", - "mkdirp": "0.5.1", - "strip-bom": "1.0.0", - "through2": "0.6.5", - "vinyl": "0.4.6" - }, - "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - }, - "graceful-fs": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", - "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", - "dev": true, - "requires": { - "natives": "1.1.1" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, - "strip-bom": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", - "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", - "dev": true, - "requires": { - "first-chunk-stream": "1.0.0", - "is-utf8": "0.2.1" - } - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": "1.0.34", - "xtend": "4.0.1" - } - }, - "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", - "dev": true, - "requires": { - "clone": "0.2.0", - "clone-stats": "0.0.1" - } - } + "unist-util-stringify-position": "^1.1.1" } }, - "whatwg-fetch": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz", - "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ=", - "dev": true + "which-pm-runs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", + "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=" }, - "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", - "dev": true, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "requires": { - "isexe": "2.0.0" + "string-width": "^1.0.2 || 2" } }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "dev": true, + "x-is-string": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz", + "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=" + }, + "xdoc-parser": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/xdoc-parser/-/xdoc-parser-3.2.3.tgz", + "integrity": "sha512-aP6TjzEX6liIoeIkZZRS4nNxJzMcQAea9S0gGjSW/hOmBc1Z6IrCIY/ehQUkguy7OI4VouJP7G2geSgvZSSYRQ==", "requires": { - "mkdirp": "0.5.1" + "antlr4ts": "^0.4.1-alpha.0", + "lodash": "^4.17.10", + "remark": "^9.0.0" } }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" } } } diff --git a/package.json b/package.json index d1d0b0a..d61a4f5 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,8 @@ "name": "mr-doc-parser", "version": "1.0.0", "description": "The official parser for Mr. Doc", - "main": "index.js", - "scripts": { - "test": "gulp" - }, + "main": "./build/index.js", + "scripts": {}, "repository": { "type": "git", "url": "git+https://github.com/mr-doc/parser.git" @@ -17,27 +15,23 @@ }, "homepage": "https://github.com/mr-doc/parser#readme", "devDependencies": { - "@types/mocha": "^2.2.45", - "@types/node": "^8.5.5", + "@types/mocha": "^2.2.48", + "@types/node": "^8.10.28", "chai": "^4.1.2", - "eslint": "^4.14.0", - "eslint-config-airbnb": "^16.1.0", - "eslint-plugin-import": "^2.2.0", - "eslint-plugin-jsx-a11y": "^6.0.3", - "eslint-plugin-react": "^7.5.1", - "gulp": "^3.9.1", - "gulp-eslint": "^4.0.0", - "gulp-mocha": "^5.0.0", - "mocha": "^4.1.0", - "mr-doc-utils": "git+https://github.com/mr-doc/mr-doc-utils.git" + "mocha": "^4.1.0" }, "dependencies": { - "@types/babel-core": "^6.25.3", - "@types/lodash": "^4.14.91", + "@types/babel-core": "^6.25.5", + "@types/lodash": "^4.14.116", + "babel-core": "^6.26.3", "babel-traverse": "^6.7.6", - "babel-core": "^6.24.1", "babylon": "^6.7.0", - "lodash": "^4.11.1", - "mr-doc-utils": "git+https://github.com/mr-doc/mr-doc-utils.git" + "lodash": "^4.17.10", + "mr-doc-utils": "github:iwatakeshi/mr-doc-utils", + "tree-crawl": "^1.0.5", + "tree-sitter": "^0.13.8", + "tree-sitter-javascript": "^0.13.5", + "tree-sitter-typescript": "^0.13.3", + "xdoc-parser": "^3.2.3" } } diff --git a/result.txt b/result.txt new file mode 100644 index 0000000..95801b4 --- /dev/null +++ b/result.txt @@ -0,0 +1,9 @@ +visit: 327.424ms +internal_module +namespace +identifier +internal_module +comment +comment +comment +comment diff --git a/src/ParserFactory.ts b/src/ParserFactory.ts new file mode 100644 index 0000000..dbd08cf --- /dev/null +++ b/src/ParserFactory.ts @@ -0,0 +1,29 @@ +import Source from "./interfaces/Source"; +import JavaScriptParser from "./lang/javascript"; +import TypeScriptParser from './lang/typescript'; +import Parser from "./lang/common/parser"; + +export default class ParserFactory { + private source: Source + private options = { + language: 'JavaScript' + } + constructor(file: Source, options: any = {}) { + this.source = file; + Object.assign(this.options, options) + } + + getParser = (): Parser => { + switch (this.options.language.toLowerCase()) { + case 'js': + case 'javascript': + return new JavaScriptParser(this.source, this.options); + case 'ts': + case 'typescript': + return new TypeScriptParser(this.source, this.options); + default: + console.log(`[mr-doc]: No parser for ${this.options.language} exists.`) + break; + } + } +} \ No newline at end of file diff --git a/src/interface.js b/src/interface.js deleted file mode 100644 index d549d1f..0000000 --- a/src/interface.js +++ /dev/null @@ -1,3 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -//# sourceMappingURL=interface.js.map \ No newline at end of file diff --git a/src/interface.js.map b/src/interface.js.map deleted file mode 100644 index 00726e0..0000000 --- a/src/interface.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"interface.js","sourceRoot":"","sources":["interface.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/src/interface.ts b/src/interface.ts deleted file mode 100644 index 21966d5..0000000 --- a/src/interface.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { SourceLocation } from "babel-types"; - -// export interface CommentContext { -// location: { start: number, end: number } -// } -export interface IFile { - name: string, - source: string, -} - - -export interface ICommentType { - type: 'leadingComments' | 'innerComments' | 'trailingComments' - context: boolean -} - -export interface ICommentContext { - location: SourceLocation, - code: string -} - -export interface IComment { - context: ICommentContext, - value: string - location: SourceLocation -} - -export interface IParseResult { - comments: IComment[], - type: string, - file: IFile -} - -export interface IParser { - parse: (file: IFile) => IParseResult -} \ No newline at end of file diff --git a/src/interfaces/ASTNode.ts b/src/interfaces/ASTNode.ts new file mode 100644 index 0000000..7b253b3 --- /dev/null +++ b/src/interfaces/ASTNode.ts @@ -0,0 +1,33 @@ +import TextRange from "./TextRange"; +import { RemarkNode } from "xdoc-parser/src/XDocParser"; +import { DocumentationNode } from "xdoc-parser/src/XDocASTNode"; + +export default interface ASTNode extends TextRange { + /** + * @property - The type of node. + */ + type: string, + /** + * @property - The context string. + */ + text: string, + /** + * @property - The node's children. + */ + children: ASTNode[] | undefined[], + /** + * @property - The context node that a comment node refers to. + */ + context: ASTNode, + /** + * @property - The properties that a ASTNode may possess. + */ + properties?: object + /** + * @property - The parsed XDoc comment. + */ + comment?: { + markdown: RemarkNode, + documentation: Partial + } +} \ No newline at end of file diff --git a/src/interfaces/Source.ts b/src/interfaces/Source.ts new file mode 100644 index 0000000..02238fc --- /dev/null +++ b/src/interfaces/Source.ts @@ -0,0 +1,5 @@ +export default interface Source { + name: string, + path: string, + text: string +} \ No newline at end of file diff --git a/src/interfaces/TextRange.ts b/src/interfaces/TextRange.ts new file mode 100644 index 0000000..b221c22 --- /dev/null +++ b/src/interfaces/TextRange.ts @@ -0,0 +1,39 @@ + +/** + * An interface that represents a range. + * + * @interface Range + */ +export interface Range { + start: number, + end: number +} + +/** + * An interface that represents the positional + * and locational ranges of a source code. + * + * @interface TextRange + */ +export default interface TextRange { + /** + * Represents a context's start and end position. + * @property position: { + * start: number, + * end: number + * } + */ + position: Range + /** + * Represents a context's row and column location. + * + * @location: { + * row: Range, + * column: Range + * } + */ + location: { + row: Range, + column: Range + } +} \ No newline at end of file diff --git a/src/javascript/index.js b/src/javascript/index.js deleted file mode 100644 index 8103514..0000000 --- a/src/javascript/index.js +++ /dev/null @@ -1,107 +0,0 @@ -'use strict'; -Object.defineProperty(exports, "__esModule", { value: true }); -const mr_doc_utils_1 = require("mr-doc-utils"); -const babylon_1 = require("babylon"); -const babel_core_1 = require("babel-core"); -const { Log } = mr_doc_utils_1.default; -const log = new Log(); -class JavaScript { - constructor() { - this.visited = new Map(); - this.comments = []; - this.docs = []; - } - /** - * Parse the file. - * @param {Object} - The file to parse. - */ - parse(file) { - this.file = file; - this.ast = babylon_1.parse(file.source, { - allowImportExportEverywhere: true, - sourceType: 'module', - plugins: [ - 'asyncGenerators', - 'classConstructorCall', - 'classProperties', - 'decorators', - 'doExpressions', - 'exportExtensions', - 'flow', - 'functionBind', - 'functionSent', - 'jsx', - 'objectRestSpread', - 'dynamicImport' - ] - }); - // DEBUG: AST - log.debug(Log.color.blue(`Parsing Javascript file: ${file.name}`)); - let types = [ - { type: 'leadingComments', context: true }, - { type: 'innerComments', context: false }, - { type: 'trailingComments', context: false }, - ]; - types.forEach(commentType => this.walk(commentType)); - return { type: 'module', file, comments: this.docs }; - } - /** - * Walk the comments. - * @param {Object} - The comment type and context to walk. - */ - walk(commentType) { - babel_core_1.traverse(this.ast, { - enter: path => { - let type = commentType.type; - const parseComment = (comment) => { - const result = this.addComment(path, comment, commentType.context); - if (result.context.code !== '') - this.docs.push(result); - }; - (path.node[type] || []).filter((comment) => { - return 'type' in comment && comment.type === 'CommentBlock'; - }).forEach(parseComment); - } - }); - } - addComment(path, comment, includeContext) { - let file = this.file; - let key = file.name + ':' + comment.loc.start.line + ':' + comment.loc.start.column; - let context = { - location: { - start: { line: 0, column: 0 }, - end: { line: 0, column: 0 }, - }, - code: '' - }; - if (!this.visited.get(key)) { - this.visited.set(key, true); - // Normalize the comments since bable strips - // the markers (/*, */, //) - switch (comment.type) { - case 'CommentBlock': - comment.value = `/*${comment.value}*/`; - break; - case 'CommentLine': comment.value = `//${comment.value}`; - } - context = { - location: path.node.loc, - code: '' - }; - if (includeContext) { - Object.defineProperty(context, 'ast', { - configurable: true, - enumerable: false, - value: path, - }); - } - if (path.parentPath && path.parentPath.node) { - let parentNode = path.parentPath.node; - context.code = this.file.source.substring(parentNode.start, parentNode.end); - } - } - return { context, value: comment.value, location: comment.loc }; - } -} -exports.default = JavaScript; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/src/javascript/index.js.map b/src/javascript/index.js.map deleted file mode 100644 index 8d1b292..0000000 --- a/src/javascript/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,+CAAgC;AAEhC,qCAAgC;AAChC,2CAAsC;AAItC,MAAM,EAAE,GAAG,EAAE,GAAG,sBAAI,CAAC;AACrB,MAAM,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;AAEtB;IAAA;QACU,YAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;QACrC,aAAQ,GAAG,EAAE,CAAC;QACd,SAAI,GAAe,EAAE,CAAC;IAoGhC,CAAC;IAjGC;;;OAGG;IACH,KAAK,CAAC,IAAsC;QAC1C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,GAAG,GAAG,eAAK,CAAC,IAAI,CAAC,MAAM,EAAE;YAC5B,2BAA2B,EAAE,IAAI;YACjC,UAAU,EAAE,QAAQ;YACpB,OAAO,EAAE;gBACP,iBAAiB;gBACjB,sBAAsB;gBACtB,iBAAiB;gBACjB,YAAY;gBACZ,eAAe;gBACf,kBAAkB;gBAClB,MAAM;gBACN,cAAc;gBACd,cAAc;gBACd,KAAK;gBACL,kBAAkB;gBAClB,eAAe;aAChB;SACF,CAAC,CAAC;QACH,aAAa;QACb,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,4BAA4B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACnE,IAAI,KAAK,GAAmB;YAC1B,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE;YAC1C,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,KAAK,EAAE;YACzC,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,KAAK,EAAE;SAC7C,CAAC;QACF,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;QACrD,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IACvD,CAAC;IACD;;;OAGG;IACK,IAAI,CAAC,WAAyB;QACpC,qBAAQ,CAAC,IAAI,CAAC,GAAG,EAAE;YACjB,KAAK,EAAE,IAAI,CAAC,EAAE;gBACZ,IAAI,IAAI,GAAiB,WAAW,CAAC,IAAI,CAAC;gBAC1C,MAAM,YAAY,GAAG,CAAC,OAAgB,EAAE,EAAE;oBACxC,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;oBACnE,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,KAAK,EAAE,CAAC;wBAC7B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC3B,CAAC,CAAC;gBAEF,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,OAA6C,EAAE,EAAE;oBAC/E,MAAM,CAAC,MAAM,IAAI,OAAO,IAAmB,OAAQ,CAAC,IAAI,KAAK,cAAc,CAAC;gBAC9E,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YAC3B,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IAEO,UAAU,CAAC,IAAc,EAAE,OAA6C,EAAE,cAAuB;QACvG,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACrB,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;QAEpF,IAAI,OAAO,GAAoB;YAC7B,QAAQ,EAAE;gBACR,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;gBAC7B,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;aAC5B;YACD,IAAI,EAAE,EAAE;SACT,CAAC;QACF,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC3B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAE5B,4CAA4C;YAC5C,2BAA2B;YAC3B,MAAM,CAAA,CAA8B,OAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;gBAClD,KAAK,cAAc;oBAAE,OAAO,CAAC,KAAK,GAAG,KAAK,OAAO,CAAC,KAAK,IAAI,CAAC;oBAC5D,KAAK,CAAC;gBACN,KAAK,aAAa,EAAE,OAAO,CAAC,KAAK,GAAG,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC;YAC3D,CAAC;YAED,OAAO,GAAG;gBACR,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG;gBACvB,IAAI,EAAE,EAAE;aACT,CAAC;YAEF,EAAE,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;gBACnB,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,EAAE;oBACpC,YAAY,EAAE,IAAI;oBAClB,UAAU,EAAE,KAAK;oBACjB,KAAK,EAAE,IAAI;iBACZ,CAAC,CAAC;YACL,CAAC;YAED,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC5C,IAAI,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;gBACtC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC;YAC9E,CAAC;QACH,CAAC;QACD,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;IAClE,CAAC;CACF;AAvGD,6BAuGC"} \ No newline at end of file diff --git a/src/javascript/index.ts b/src/javascript/index.ts deleted file mode 100644 index 12e993c..0000000 --- a/src/javascript/index.ts +++ /dev/null @@ -1,116 +0,0 @@ -'use strict'; -import * as _ from "lodash"; -import Util from 'mr-doc-utils'; -import { File, Comment, CommentBlock, CommentLine } from 'babel-types'; -import { parse } from 'babylon'; -import { traverse } from 'babel-core'; -import { IParser, IParseResult, ICommentType, ICommentContext, IComment } from '../interface'; -import { NodePath, Node } from "babel-traverse"; - -const { Log } = Util; -const log = new Log(); - -export default class JavaScript implements IParser { - private visited = new Map(); - private comments = []; - private docs: IComment[] = []; - private ast: File; - private file: { name: string, source: string }; - /** - * Parse the file. - * @param {Object} - The file to parse. - */ - parse(file: { name: string, source: string }): IParseResult { - this.file = file - this.ast = parse(file.source, { - allowImportExportEverywhere: true, - sourceType: 'module', - plugins: [ - 'asyncGenerators', - 'classConstructorCall', - 'classProperties', - 'decorators', - 'doExpressions', - 'exportExtensions', - 'flow', - 'functionBind', - 'functionSent', - 'jsx', - 'objectRestSpread', - 'dynamicImport' - ] - }); - // DEBUG: AST - log.debug(Log.color.blue(`Parsing Javascript file: ${file.name}`)); - let types: ICommentType[] = [ - { type: 'leadingComments', context: true }, - { type: 'innerComments', context: false }, - { type: 'trailingComments', context: false }, - ]; - types.forEach(commentType => this.walk(commentType)); - return { type: 'module', file, comments: this.docs }; - } - /** - * Walk the comments. - * @param {Object} - The comment type and context to walk. - */ - private walk(commentType: ICommentType) { - traverse(this.ast, { - enter: path => { - let type: (keyof Node) = commentType.type; - const parseComment = (comment: Comment) => { - const result = this.addComment(path, comment, commentType.context); - if (result.context.code !== '') - this.docs.push(result); - }; - - (path.node[type] || []).filter((comment: CommentBlock | CommentLine | Comment) => { - return 'type' in comment && (comment).type === 'CommentBlock'; - }).forEach(parseComment); - } - }); - } - - private addComment(path: NodePath, comment: CommentBlock | CommentLine | Comment, includeContext: boolean): IComment { - let file = this.file; - let key = file.name + ':' + comment.loc.start.line + ':' + comment.loc.start.column; - - let context: ICommentContext = { - location: { - start: { line: 0, column: 0 }, - end: { line: 0, column: 0 }, - }, - code: '' - }; - if (!this.visited.get(key)) { - this.visited.set(key, true); - - // Normalize the comments since bable strips - // the markers (/*, */, //) - switch((comment).type) { - case 'CommentBlock': comment.value = `/*${comment.value}*/`; - break; - case 'CommentLine': comment.value = `//${comment.value}`; - } - - context = { - location: path.node.loc, - code: '' - }; - - if (includeContext) { - Object.defineProperty(context, 'ast', { - configurable: true, - enumerable: false, - value: path, - }); - } - - if (path.parentPath && path.parentPath.node) { - let parentNode = path.parentPath.node; - context.code = this.file.source.substring(parentNode.start, parentNode.end); - } - } - return { context, value: comment.value, location: comment.loc }; - } -} \ No newline at end of file diff --git a/src/lang/common/ast.ts b/src/lang/common/ast.ts new file mode 100644 index 0000000..9806619 --- /dev/null +++ b/src/lang/common/ast.ts @@ -0,0 +1,43 @@ +import { SyntaxNode } from "tree-sitter"; +import { text } from "../../utils/text"; +import range from "../../utils/range"; +import Source from "../../interfaces/Source"; +import xdoc from 'xdoc-parser'; +import * as _ from 'lodash' +import ASTNode from "../../interfaces/ASTNode"; + +export function isASTNode(object: object): object is ASTNode { + return object && 'type' in object && 'text' in object && 'children' in object; +} + +export function createASTNode(source: Source, node: SyntaxNode): ASTNode +export function createASTNode(source: Source, node: SyntaxNode, properties: object) +export function createASTNode(source: Source, node: SyntaxNode, children: object[]): ASTNode +export function createASTNode(source: Source, node: SyntaxNode, children: object[], properties: object) +export function createASTNode(source: Source, node: SyntaxNode, context: ASTNode, document: boolean): ASTNode +export function createASTNode(source: Source, node: SyntaxNode, arg1?: any, arg2?: any): ASTNode { + + let context, children = [], document = typeof arg2 === 'boolean' && arg2 === true, properties; + + if (_.isPlainObject(arg1) && !isASTNode(arg1)) { + properties = arg1; + } else if (_.isPlainObject(arg1) && isASTNode(arg1)) { + context = arg1; + } else if (_.isArray(arg1)) { + children = arg1; + } + + if (_.isPlainObject(arg2)) { + properties = arg2; + } + + return { + type: node.type, + text: text(source, node), + ...range(node), + context, + children, + comment: document ? xdoc(source.text).parse() : undefined, + properties, + } +} diff --git a/src/lang/common/node.ts b/src/lang/common/node.ts new file mode 100644 index 0000000..1bfa183 --- /dev/null +++ b/src/lang/common/node.ts @@ -0,0 +1,16 @@ +import { SyntaxNode } from "tree-sitter"; +import Visitor from "./visitor"; + +export interface TreeSitterNode { + visit(visitor: Visitor): void +} + +/** + * A class that wraps a SyntaxNode as a Node + */ +export class Node implements TreeSitterNode { + constructor(public syntaxNode: SyntaxNode) { } + visit = (visitor: Visitor): void => { + visitor.visitNode(this.syntaxNode); + } +} \ No newline at end of file diff --git a/src/lang/common/parser.ts b/src/lang/common/parser.ts new file mode 100644 index 0000000..de5da0a --- /dev/null +++ b/src/lang/common/parser.ts @@ -0,0 +1,31 @@ +import Source from "../../interfaces/Source"; +import { Tree } from "tree-sitter"; +import ASTNode from "../../interfaces/ASTNode"; +import { LogOptions } from "mr-doc-utils"; +import { XDocParserOptions } from "xdoc-parser/src/XDocParser"; + +export interface ParserOptions { + log: LogOptions, + documentation: XDocParserOptions, + language?: string +} + +export default abstract class Parser { + private source_: Source + protected options: ParserOptions + constructor(source: Source, options: Partial) { + this.source_ = source; + this.options = Object.assign((options || {}), { + log: { + enabled: true, + levels: ['info', 'warn', 'error'] + } as LogOptions, + documentation: { + } as XDocParserOptions, + }); + } + get source(): Source { return this.source_; } + get language(): string { return this.options.language; } + abstract parse(): ASTNode[] + abstract get tree(): Tree +} \ No newline at end of file diff --git a/src/lang/common/visitor.ts b/src/lang/common/visitor.ts new file mode 100644 index 0000000..ffac09c --- /dev/null +++ b/src/lang/common/visitor.ts @@ -0,0 +1,22 @@ +import { SyntaxNode } from "tree-sitter"; +import ASTNode from "../../interfaces/ASTNode"; +import { LogOptions, LogInterface } from "mr-doc-utils"; +import { XDocParserOptions } from "xdoc-parser/src/XDocParser"; +import ParserLogger from "../../utils/log"; + +export interface VisitorOptions { + log: LogOptions, + documentation: XDocParserOptions +} + +export default abstract class Visitor { + protected options: Partial + protected logger: ParserLogger + constructor(options?: Partial) { + this.options = options; + this.logger = new ParserLogger(this.options.log); + } + abstract getAST(): ASTNode[] + abstract visitNode(node: SyntaxNode, properties?: object): ASTNode + abstract visitChildren(nodes: SyntaxNode[], properties?: object): ASTNode[] +} \ No newline at end of file diff --git a/src/lang/javascript/index.ts b/src/lang/javascript/index.ts new file mode 100644 index 0000000..1f8c10f --- /dev/null +++ b/src/lang/javascript/index.ts @@ -0,0 +1,36 @@ +import * as TreeSitter from 'tree-sitter'; +import * as JavaScript from 'tree-sitter-javascript'; +import Parser from '../common/parser'; +import Source from '../../interfaces/Source'; +import { JavaScriptVisitor } from './visitor'; +import walk from '../../utils/walk'; +import ASTNode from '../../interfaces/ASTNode'; + +/** + * A class that parses JavaScript comments. + * + * # API + * + * @class JavaScriptParser + * @implements IParser + * @export default + */ +export default class JavaScriptParser extends Parser { + private parser: TreeSitter; + private tree_: TreeSitter.Tree; + constructor(source: Source, options: any) { + super(source, options); + this.parser = new TreeSitter(); + this.parser.setLanguage(JavaScript); + this.tree_ = this.parser.parse(this.source.text); + } + parse(): ASTNode[] { + const visitor = new JavaScriptVisitor(this.source, this.options); + const nodes = walk(this.tree_.rootNode); + nodes.visit(visitor) + return visitor.getAST(); + } + get tree (): TreeSitter.Tree { + return this.tree_; + } +} \ No newline at end of file diff --git a/src/lang/javascript/properties.ts b/src/lang/javascript/properties.ts new file mode 100644 index 0000000..c4aa4e7 --- /dev/null +++ b/src/lang/javascript/properties.ts @@ -0,0 +1,16 @@ +export interface JavaScriptProperties { + exports: Partial + inheritance: Partial + namespace: boolean, + module: boolean +} + +export interface JavaScriptExports { + export: boolean, + default: boolean +} + +export interface JavaScriptInheritance { + extends: boolean, + implements: boolean +} \ No newline at end of file diff --git a/src/lang/javascript/visitor.ts b/src/lang/javascript/visitor.ts new file mode 100644 index 0000000..555f6f9 --- /dev/null +++ b/src/lang/javascript/visitor.ts @@ -0,0 +1,351 @@ +import { createASTNode } from "../common/ast"; +import { isJavaDocComment } from "../../utils/comment"; +import { sibling } from "../../utils/sibling"; +import { SyntaxNode } from "tree-sitter"; +import * as _ from 'lodash'; +import log, { ErrorType } from "../../utils/log"; +import match from "../../utils/match"; +import Source from "../../interfaces/Source"; +import Visitor, { VisitorOptions } from "../common/visitor"; +import ASTNode from "../../interfaces/ASTNode"; +import { JavaScriptProperties, JavaScriptInheritance } from "./properties"; + +/** + * A class that visits ASTNodes from a TypeScript tree. + */ +export class JavaScriptVisitor extends Visitor { + private ast: ASTNode[] = [] + private source: Source + constructor(source: Source, options: Partial) { + super(options); + this.source = source; + } + + /** + * Determines whether a node has inheritance + */ + private hasInheritance(node: SyntaxNode) { + let inherits = false; + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match(child, 'extends', 'implements')) { + inherits = true; + } + } + return inherits + } + + /** + * Returns a node's inheritance type + */ + private getInheritanceType(node: SyntaxNode) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match(child, 'extends')) { + return 'extends'; + } + + if (match(child, 'implements')) { + return 'implements'; + } + } + } + + /** + * Determines whether an export is default + */ + private hasDefaultExport(node: SyntaxNode): boolean { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match(child, 'default')) { + return true; + } + } + return false; + } + + /** + * Returns only the comments from a node's children. + */ + private filterType(node: SyntaxNode, type: string): SyntaxNode[] { + let children: SyntaxNode[] = []; + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match(child, type)) { + children.push(child); + } + } + return children; + } + + getAST(): ASTNode[] { + return this.ast; + } + + /* Visitors */ + + visitNode = ( + node: SyntaxNode, + properties?: Partial + ) => { + switch (node.type) { + case 'program': + this.ast = this.visitProgram(node); + break; + case 'comment': + return this.visitComment(node); + case 'MISSING': + case 'ERROR': + this.logger.report(this.source, node, ErrorType.TreeSitterParseError); + break; + default: + + /* Match other non-terminals */ + + if (match(node, + 'constraint', + 'formal_parameters', 'required_parameter', 'rest_parameter', + 'type_identifier', 'type_parameters', 'type_parameter', 'type_annotation', + 'object_type', 'predefined_type', 'parenthesized_type', 'literal_type', + 'intersection_type', 'union_type', + 'class_body', + 'extends_clause', + 'unary_expression', 'binary_expression', 'parenthesized_expression', 'member_expression', + 'statement_block', 'return_statement', 'export_statement', 'expression_statement', + // A call_signature can also be a non-contextual node + 'call_signature', + 'internal_module', + 'if_statement' + )) { + return this.visitNonTerminal(node, properties) + } + + /* Match terminals */ + if (match(node, + 'identifier', 'extends', 'property_identifier', 'accessibility_modifier', + 'null', 'undefined', 'return', + 'get', 'function', 'namespace', 'if', 'const' + )) { + return this.visitTerminal(node); + } + + this.logger.report(this.source, node, ErrorType.NodeTypeNotYetSupported); + return; + } + } + + visitChildren = (nodes: SyntaxNode[]): ASTNode[] => { + let children: ASTNode[] = []; + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + if (!node.type.match(/[<>(){},:;\[\]&|=\+\-\*\/!.]/) && node.type !== '...') { + const child = this.visitNode(node); + if (child) children.push(child); + } + } + return children; + } + + private visitProgram = (node: SyntaxNode): ASTNode[] => { + let visited = {}, + getStartLocation = (n: ASTNode) => `${n.location.row.start}:${n.location.column.start}`; + // A program can have modules, namespaces, comments as its children + // The first step is to parse all the comments in the root node + let comments = this.visitChildren(this.filterType(node, 'comment')); + // Parse the namespaces in expression_statement + // let namespaces = this.visitChildren(this.filterType(node, 'expression_statement')); + // Parse the export statements in the root node + let exports = this.visitChildren(this.filterType(node, 'export_statement')); + + // Get the visited context nodes + for (let i = 0; i < comments.length; i++) { + const comment = comments[i]; + const context = comment; + visited[getStartLocation(context)] = true; + } + + // Exports are oddballs since some exports may reference + // a type/node that may have been commented. + // We'll first need to filter the ones we have visited + _.remove(exports, x => visited[getStartLocation(x)]); + + // From the ones we have not visited, we'll need to modify + // the node properties of each context in a comment node that + // matches the ones we have not visited. + const matched = {}; + comments = _.compact( + comments.map(comment => { + for (let i = 0; i < exports.length; i++) { + const export_ = exports[i]; + const context = comment.context; + for (let j = 0; context && j < context.children.length; j++) { + if (context.children[i] && context.children[i].type === export_.type) { + matched[getStartLocation(export_)] = true; + comment.context.properties = Object.assign( + comment.context.properties || {}, + export_.properties + ); + } + } + } + return comment; + })); + + // Removed the matched exports + _.remove(exports, x => matched[getStartLocation(x)]) + + return [].concat(comments).concat(exports); + } + + private visitComment = (node: SyntaxNode): ASTNode => { + if (isJavaDocComment(this.source, node)) { + const nextSibling = sibling(node); + if (nextSibling) { + return createASTNode(this.source, node, this.visitContext(nextSibling, {}), true) + } + } + } + + /** + * Visit the contextual node + * + * # Remark + * + * A node is considered contextual when a comment is visited and the node is its sibling. + */ + private visitContext = (node: SyntaxNode, properties?: Partial): ASTNode => { + switch (node.type) { + case 'export_statement': + return this.visitExportStatement(node, properties); + case 'expression_statement': + return this.visitExpressionStatement(node, properties); + case 'class': + return this.visitClass(node, properties) + case 'function': + case 'call_signature': + case 'method_signature': + case 'property_signature': + case 'public_field_definition': + case 'method_definition': + case 'lexical_declaration': + return this.visitNonTerminal(node, properties); + default: + this.logger.report(this.source, node, ErrorType.NodeTypeNotYetSupported); + return; + } + } + + /* Statements */ + + private visitExportStatement = (node: SyntaxNode, properties?: Partial): ASTNode => { + let children = node.children, defaultExport = false; + // Remove 'export' since it's always first in the array + children.shift(); + if (this.hasDefaultExport(node)) { + defaultExport = true; + // Remove 'default' export + children.shift(); + } + const child = children.shift(); + return this.visitNode(child, { exports: { export: true, default: defaultExport } }); + } + + private visitExpressionStatement = (node: SyntaxNode, properties: Partial): ASTNode => { + let children = node.children; + const child = children.shift(); + + if (match(child, 'internal_module')) { + return this.visitInternalModule(child, properties) + } + + if (match(child, 'function')) { + if (properties) return this.visitContext(child); + } + + return this.visitNonTerminal(child) + } + + /* Modules */ + + private visitInternalModule = (node: SyntaxNode, properties?: Partial): ASTNode => { + let children: ASTNode[] = node.children.map(child => { + if (match(child, 'statement_block')) { + return createASTNode(this.source, node, this.visitChildren(this.filterType(child, 'comment'))) + } + return this.visitNode(child); + }); + return createASTNode(this.source, node, children, Object.assign(properties || {}, { namespace: true })); + } + + + /* Declarations */ + + private visitClass = (node: SyntaxNode, properties?: Partial): ASTNode => { + // Since 'interface' or 'class' is always first in the array + // we'll need to remove it from the array. + let children = node.children; + const interface_ = children.shift(); + let extends_ = false, implements_ = false; + if (this.hasInheritance(node)) { + const inheritance = this.getInheritanceType(node) + extends_ = inheritance === 'extends'; + implements_ = inheritance === 'implements'; + } + + const node_ = createASTNode( + this.source, + node, + this.visitChildren(children), + Object.assign(properties || {}, { + inheritance: { + implements: implements_, + extends: extends_ + } as JavaScriptInheritance + })); + + if (match(node, 'class')) { + return node_; + } + // Overwrite the node type from 'interface_declaration' to 'interface' + return Object.assign(node_, { type: interface_.type }) + } + + /* Non-terminals */ + + private visitNonTerminal = (node: SyntaxNode, properties?: Partial): ASTNode => { + let children = node.children; + // Handle special cases where some non-terminals + // contain comments which is what we care about + if (match(node, 'class_body', 'object_type')) { + children = this.filterType(node, 'comment'); + } + // Handle special cases where export statements have node properties + if (match(node, 'export_statement')) { + return this.visitExportStatement(node); + } + + // Handle special cases where an internal module contains other nodes + if (match(node, 'internal_module')) { + return this.visitInternalModule(node, properties); + } + + // Handle special cases where an intermal_module can exist in an expression_statement + if (match(node, 'expression_statement')) { + return this.visitExpressionStatement(node, properties); + } + + // Handle special cases where a function has a statement_block + if (match(node, 'function') || match(node, 'method_definition')) { + _.remove(children, child => match(child, 'statement_block')) + return createASTNode(this.source, node, this.visitChildren(children), properties); + } + + return createASTNode(this.source, node, this.visitChildren(children), properties); + } + + /* Terminals */ + + private visitTerminal = (node: SyntaxNode): ASTNode => { + return createASTNode(this.source, node) + } +} \ No newline at end of file diff --git a/src/lang/typescript/index.ts b/src/lang/typescript/index.ts new file mode 100644 index 0000000..afa0e24 --- /dev/null +++ b/src/lang/typescript/index.ts @@ -0,0 +1,38 @@ +import * as TreeSitter from 'tree-sitter'; +import * as TypeScript from 'tree-sitter-typescript'; +import Parser from '../common/parser'; +import Source from '../../interfaces/Source'; +import walk from '../../utils/walk'; +import { TypeScriptVisitor } from './visitor'; +import ASTNode from '../../interfaces/ASTNode'; + + +/** + * A class that parses JavaScript comments. + * + * # API + * + * @class JavaScriptParser + * @implements IParser + * @export default + */ +export default class TypeScriptParser extends Parser { + private parser: TreeSitter; + private tree_: TreeSitter.Tree; + constructor(source: Source, options: any) { + super(source, options); + this.parser = new TreeSitter(); + this.parser.setLanguage(TypeScript); + this.tree_ = this.parser.parse(this.source.text); + } + parse = (): ASTNode[] => { + const visitor = new TypeScriptVisitor(this.source, this.options); + const nodes = walk(this.tree_.rootNode); + nodes.visit(visitor) + return visitor.getAST(); + } + + get tree (): TreeSitter.Tree { + return this.tree_; + } +} diff --git a/src/lang/typescript/properties.ts b/src/lang/typescript/properties.ts new file mode 100644 index 0000000..da562f0 --- /dev/null +++ b/src/lang/typescript/properties.ts @@ -0,0 +1,16 @@ +export interface TypeScriptProperties { + exports: Partial + inheritance: Partial + namespace: boolean, + module: boolean +} + +export interface TypeScriptExports { + export: boolean, + default: boolean +} + +export interface TypeScriptInheritance { + extends: boolean, + implements: boolean +} \ No newline at end of file diff --git a/src/lang/typescript/visitor.ts b/src/lang/typescript/visitor.ts new file mode 100644 index 0000000..7839dfd --- /dev/null +++ b/src/lang/typescript/visitor.ts @@ -0,0 +1,354 @@ +import { isJavaDocComment, isLegalComment } from "../../utils/comment"; +import { sibling } from "../../utils/sibling"; +import { SyntaxNode } from "tree-sitter"; +import * as _ from 'lodash'; +import log, { ErrorType } from "../../utils/log"; +import match from "../../utils/match"; +import Source from "../../interfaces/Source"; +import Visitor, { VisitorOptions } from "../common/visitor"; +import ASTNode from "../../interfaces/ASTNode"; +import { createASTNode } from "../common/ast"; +import { TypeScriptProperties, TypeScriptInheritance } from "./properties"; + +/** + * A class that visits ASTNodes from a TypeScript tree. + */ +export class TypeScriptVisitor extends Visitor { + private ast: ASTNode[] = [] + private source: Source + constructor(source: Source, options: Partial) { + super(options) + this.source = source; + } + + /** + * Determines whether a node has inheritance + */ + private hasInheritance(node: SyntaxNode) { + let inherits = false; + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match(child, 'extends', 'implements')) { + inherits = true; + } + } + return inherits + } + + /** + * Returns a node's inheritance type + */ + private getInheritanceType(node: SyntaxNode) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match(child, 'extends')) { + return 'extends'; + } + + if (match(child, 'implements')) { + return 'implements'; + } + } + } + + /** + * Determines whether an export is default + */ + private hasDefaultExport(node: SyntaxNode): boolean { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match(child, 'default')) { + return true; + } + } + return false; + } + + /** + * Returns only the comments from a node's children. + */ + private filterType(node: SyntaxNode, type: string): SyntaxNode[] { + let children: SyntaxNode[] = []; + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (match(child, type)) { + children.push(child); + } + } + return children; + } + + getAST(): ASTNode[] { + return this.ast; + } + + /* Visitors */ + + visitNode = ( + node: SyntaxNode, + properties?: Partial + ) => { + switch (node.type) { + case 'program': + this.ast = this.visitProgram(node); + break; + case 'comment': + return this.visitComment(node); + case 'MISSING': + case 'ERROR': + this.logger.report(this.source, node, ErrorType.TreeSitterParseError); + break; + default: + + /* Match other non-terminals */ + + if (match(node, + 'constraint', + 'formal_parameters', 'required_parameter', 'rest_parameter', + 'type_identifier', 'type_parameters', 'type_parameter', 'type_annotation', + 'object_type', 'predefined_type', 'parenthesized_type', 'literal_type', + 'intersection_type', 'union_type', + 'class_body', + 'extends_clause', + 'unary_expression', 'binary_expression', 'member_expression', + 'statement_block', 'return_statement', 'export_statement', 'expression_statement', + // A call_signature can also be a non-contextual node + 'call_signature', + 'internal_module', + 'variable_declarator', + 'object' + )) { + return this.visitNonTerminal(node, properties) + } + + /* Match terminals */ + if (match(node, + 'identifier', 'extends', 'property_identifier', 'accessibility_modifier', + 'string', 'void', 'boolean', 'null', 'undefined', 'number', 'return', + 'get', 'function', 'namespace', 'const' + )) { + return this.visitTerminal(node); + } + this.logger.report(this.source, node, ErrorType.NodeTypeNotYetSupported); + break; + } + } + + visitChildren = (nodes: SyntaxNode[]): ASTNode[] => { + let children: ASTNode[] = []; + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + if (!node.type.match(/[<>(){},:;\[\]&|=\+\-\*\/]/) && node.type !== '...') { + const child = this.visitNode(node); + if (child) children.push(child); + } + } + return children; + } + + private visitProgram = (node: SyntaxNode): ASTNode[] => { + let visited = {}, + getStartLocation = (n: ASTNode) => `${n.location.row.start}:${n.location.column.start}`; + // A program can have modules, namespaces, comments as its children + // The first step is to parse all the comments in the root node + let comments = this.visitChildren(this.filterType(node, 'comment')); + // Parse the namespaces in expression_statement + let namespaces = this.visitChildren(this.filterType(node, 'expression_statement')); + // Parse the export statements in the root node + let exports = this.visitChildren(this.filterType(node, 'export_statement')); + + // Get the visited context nodes + for (let i = 0; i < comments.length; i++) { + const comment = comments[i]; + const context = comment; + visited[getStartLocation(context)] = true; + } + + // Remove the visited nodes from namespaces array + _.remove(namespaces, x => visited[getStartLocation(x)]); + + // Exports are oddballs since some exports may reference + // a type/node that may have been commented. + // We'll first need to filter the ones we have visited + _.remove(exports, x => visited[getStartLocation(x)]); + + // From the ones we have not visited, we'll need to modify + // the node properties of each context in a comment node that + // matches the ones we have not visited. + const matched = {}; + comments = _.compact( + comments.map(comment => { + for (let i = 0; i < exports.length; i++) { + const export_ = exports[i]; + const context = comment.context; + for (let j = 0; context && j < context.children.length; j++) { + if (context.children[i] && context.children[i].type === export_.type) { + matched[getStartLocation(export_)] = true; + comment.context.properties = Object.assign( + comment.context.properties || {}, + export_.properties + ); + } + } + } + return comment; + })); + + // Removed the matched exports + _.remove(exports, x => matched[getStartLocation(x)]) + + return [].concat(comments).concat(namespaces).concat(exports); + } + + private visitComment = (node: SyntaxNode): ASTNode => { + if (isJavaDocComment(this.source, node) && !isLegalComment(this.source, node)) { + const nextSibling = sibling(node); + if (nextSibling) { + return createASTNode(this.source, node, this.visitContext(nextSibling, {}), true) + } + } + } + + /** + * Visit the contextual node + * + * # Remark + * + * A node is considered contextual when a comment is visited and the node is its sibling. + */ + private visitContext = (node: SyntaxNode, properties?: Partial): ASTNode => { + switch (node.type) { + case 'export_statement': + return this.visitExportStatement(node, properties); + case 'expression_statement': + return this.visitExpressionStatement(node, properties); + case 'class': + case 'interface_declaration': + return this.visitClassOrInterface(node, properties) + case 'function': + case 'call_signature': + case 'method_signature': + case 'property_signature': + case 'public_field_definition': + case 'method_definition': + case 'lexical_declaration': + return this.visitNonTerminal(node, properties); + default: + this.logger.report(this.source, node, ErrorType.NodeTypeNotYetSupported); + break; + } + } + + /* Statements */ + + private visitExportStatement = (node: SyntaxNode, properties?: Partial): ASTNode => { + let children = node.children, defaultExport = false; + // Remove 'export' since it's always first in the array + children.shift(); + if (this.hasDefaultExport(node)) { + defaultExport = true; + // Remove 'default' export + children.shift(); + } + const child = children.shift(); + return this.visitNode(child, { exports: { export: true, default: defaultExport } }); + } + + private visitExpressionStatement = (node: SyntaxNode, properties: Partial): ASTNode => { + let children = node.children; + const child = children.shift(); + + if (match(child, 'internal_module')) { + return this.visitInternalModule(child, properties) + } + + if (match(child, 'function')) { + if (properties) return this.visitContext(child, properties); + } + + return this.visitNonTerminal(child) + } + + /* Modules */ + + private visitInternalModule = (node: SyntaxNode, properties?: Partial): ASTNode => { + let children: ASTNode[] = node.children.map(child => { + if (match(child, 'statement_block')) { + return createASTNode(this.source, node, this.visitChildren(this.filterType(child, 'comment'))) + } + return this.visitNode(child); + }); + return createASTNode(this.source, node, children, Object.assign(properties || {}, { namespace: true })); + } + + + /* Declarations */ + + private visitClassOrInterface = (node: SyntaxNode, properties?: Partial): ASTNode => { + // Since 'interface' or 'class' is always first in the array + // we'll need to remove it from the array. + let children = node.children; + const interface_ = children.shift(); + let extends_ = false, implements_ = false; + if (this.hasInheritance(node)) { + const inheritance = this.getInheritanceType(node) + extends_ = inheritance === 'extends'; + implements_ = inheritance === 'implements'; + } + + const node_ = createASTNode( + this.source, + node, + this.visitChildren(children), + Object.assign(properties || {}, { + inheritance: { + implements: implements_, + extends: extends_ + } as TypeScriptInheritance + })); + + if (match(node, 'class')) { + return node_; + } + // Overwrite the node type from 'interface_declaration' to 'interface' + return Object.assign(node_, { type: interface_.type }) + } + + /* Non-terminals */ + + private visitNonTerminal = (node: SyntaxNode, properties?: Partial): ASTNode => { + let children = node.children; + // Handle special cases where some non-terminals + // contain comments which is what we care about + if (match(node, 'class_body', 'object_type')) { + children = this.filterType(node, 'comment'); + } + // Handle special cases where export statements have node properties + if (match(node, 'export_statement')) { + return this.visitExportStatement(node); + } + + // Handle special cases where an internal module contains other nodes + if (match(node, 'internal_module')) { + return this.visitInternalModule(node, properties); + } + + // Handle special cases where an intermal_module can exist in an expression_statement + if (match(node, 'expression_statement')) { + return this.visitExpressionStatement(node, properties); + } + + if (match(node, 'function') || match(node, 'method_definition')) { + _.remove(children, child => match(child, 'statement_block')) + return createASTNode(this.source, node, this.visitChildren(children), properties); + } + + return createASTNode(this.source, node, this.visitChildren(children), properties); + } + + /* Terminals */ + + private visitTerminal = (node: SyntaxNode): ASTNode => { + return createASTNode(this.source, node) + } +} \ No newline at end of file diff --git a/src/utils/benchmark.ts b/src/utils/benchmark.ts new file mode 100644 index 0000000..8b78d70 --- /dev/null +++ b/src/utils/benchmark.ts @@ -0,0 +1,10 @@ +export default function benchmark( + label: string, + f: (x: T2) => T, + ...args: T2[] +): T { + console.time(label) + const result = f.apply(null, args); + console.timeEnd(label); + return result; +} \ No newline at end of file diff --git a/src/utils/comment.ts b/src/utils/comment.ts new file mode 100644 index 0000000..74adf60 --- /dev/null +++ b/src/utils/comment.ts @@ -0,0 +1,43 @@ +import { SyntaxNode } from "tree-sitter"; +import match from "./match"; +import Source from "../interfaces/Source"; + +export const XDocRegex = /@(\w+)([^{[(\n]*)?([\{\[\(][\s\S]*[\}\]\)]([\s]*(=|-)>.*)?)?([\s]*-(.)*)?/gmi; + +export function isLegalComment (source: Source, node: SyntaxNode) { + const possibleTexts = [ + 'copyright', + 'terms and conditions', + 'license', + 'all rights reserved' + ]; + if (match(node, 'comment')) { + return possibleTexts.map(text => + source.text + .substring(node.startIndex, node.endIndex) + .toLowerCase() + .includes(text) + ).includes(true); + } +} + +export function isJavaDocComment(source: Source, node: SyntaxNode) { + const comment = source.text.substring(node.startIndex, node.endIndex); + // regexr.com/3ejvb + return /(\/\*\*)((\s*)(.*?)(\s))*(\*\/)/.test(comment) +} + +export function isXDocComment(source:string, node?: SyntaxNode) { + let comment = source; + if (node) comment = source.substring(node.startIndex, node.endIndex); + return XDocRegex.test(comment); +} + +export function isXDocCommentBlock(source: string, node: SyntaxNode) { + const comment = source.substring(node.startIndex, node.endIndex); + return /#API/.test(comment) || /\`\`\`xdoc/.test(comment) +} + +export function isXDocCommentFragment(source: string, node: SyntaxNode) { + return !isXDocCommentBlock(source, node) && isXDocComment(source, node); +} \ No newline at end of file diff --git a/src/utils/log.ts b/src/utils/log.ts new file mode 100644 index 0000000..7b3b887 --- /dev/null +++ b/src/utils/log.ts @@ -0,0 +1,30 @@ +import { Log, LogOptions } from 'mr-doc-utils'; +import Source from '../interfaces/Source'; +import { SyntaxNode } from 'tree-sitter'; +import range from './range'; + +export enum ErrorType { + NodeTypeNotYetSupported, + TreeSitterParseError +} + +export default class ParserLogger extends Log { + constructor(options?: LogOptions) { + super('mr-doc::parser', options); + } + report = (source: Source, node: SyntaxNode, error: ErrorType): void => { + const location = range(node).location; + const sameLine = location.row.start === location.row.end; + const getLineRange = () => sameLine ? location.row.start + 1 : location.row.start + 1 + ' - ' + location.row.end + 1; + const culprit = `Line${sameLine ? '' : 's'} ${getLineRange()} in '${source.path}'`; + switch (error) { + case ErrorType.NodeTypeNotYetSupported: + this.info(`'${node.type.replace(/[_]/g, ' ')}' is not yet supported:\n${culprit}`) + break; + case ErrorType.TreeSitterParseError: + this.error(`'tree-sitter' was not able to parse the program:\n${culprit}`) + default: + break; + } + } +} \ No newline at end of file diff --git a/src/utils/match.ts b/src/utils/match.ts new file mode 100644 index 0000000..a7a565e --- /dev/null +++ b/src/utils/match.ts @@ -0,0 +1,19 @@ +import { SyntaxNode } from "tree-sitter"; + +/** + * Determines whether a node is a certain type. + * ``` + * @param node: SyntaxNode - The node to compare. + * @param type: string - The node type to match. + * @return: boolean + * ``` + */ +export default function match(node: SyntaxNode, ...types: string[]): boolean { + for (let i = 0; i < types.length; i++) { + const type = types[i]; + if (node.type === type) { + return true; + } + } + return false; +} \ No newline at end of file diff --git a/src/utils/range.ts b/src/utils/range.ts new file mode 100644 index 0000000..d4e1534 --- /dev/null +++ b/src/utils/range.ts @@ -0,0 +1,15 @@ +import * as Parser from 'tree-sitter'; +import TextRange from '../interfaces/TextRange'; + +export default function range(node: Parser.SyntaxNode): TextRange { + return { + position: { + start: node.startIndex, + end: node.endIndex + }, + location: { + row: { start: node.startPosition.row, end: node.endPosition.row }, + column: { start: node.startPosition.column, end: node.endPosition.column } + } + } +} \ No newline at end of file diff --git a/src/utils/sibling.ts b/src/utils/sibling.ts new file mode 100644 index 0000000..81d1bb0 --- /dev/null +++ b/src/utils/sibling.ts @@ -0,0 +1,17 @@ +import { SyntaxNode } from "tree-sitter"; + +export function sibling( + node: SyntaxNode, + children?: SyntaxNode[], + filter?: () => boolean +) { + if (node) { + if (children) { + const index = filter ? + children.filter(filter).indexOf(node) : + children.indexOf(node); + return children[index + 1]; + } + return node.nextSibling; + } +} \ No newline at end of file diff --git a/src/utils/text.ts b/src/utils/text.ts new file mode 100644 index 0000000..c757993 --- /dev/null +++ b/src/utils/text.ts @@ -0,0 +1,14 @@ +import { SyntaxNode } from "tree-sitter"; +import Source from "../interfaces/Source"; + +/** + * Returns the context string + * + * # API + * + * @param source: IFile - The source file. + * @param node: SyntaxNode - The syntax node. + */ +export function text(source: Source, node: SyntaxNode) { + return source.text.substring(node.startIndex, node.endIndex); +} \ No newline at end of file diff --git a/src/utils/walk.ts b/src/utils/walk.ts new file mode 100644 index 0000000..1f3437c --- /dev/null +++ b/src/utils/walk.ts @@ -0,0 +1,7 @@ +import { SyntaxNode } from "tree-sitter"; +import { Node } from '../lang/common/node' +export default function walk(node: SyntaxNode) { + let node_ = new Node(node); + node_.syntaxNode.children.map(child => walk(child)) + return node_; +} \ No newline at end of file diff --git a/test/fixtures/test.js b/test/fixtures/test.js deleted file mode 100644 index ce11e42..0000000 --- a/test/fixtures/test.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @desc blah - */ -function foo() { - return "" -} \ No newline at end of file diff --git a/test/index.js b/test/index.js deleted file mode 100644 index d12facb..0000000 --- a/test/index.js +++ /dev/null @@ -1,18 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const fs_1 = require("fs"); -const path_1 = require("path"); -/* eslint-env mocha */ -const assert = require('chai').assert; -const Parser = require('../').default; -describe('Parser', () => { - describe('JavaScript (Babel)', function () { - const source = fs_1.readFileSync(path_1.join(__dirname, 'fixtures') + '/test.js', 'utf8'); - it('should return an object containing the parsed comments', () => { - const result = new Parser({ language: 'js' }).parse({ name: 'index.js', source }); - assert.isObject(result); - assert.isTrue(result.comments.length === 1); - }); - }); -}); -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/test/index.js.map b/test/index.js.map deleted file mode 100644 index 7e09ee6..0000000 --- a/test/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;AAAA,2BAAkC;AAClC,+BAA4B;AAE5B,sBAAsB;AACtB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;AACtC,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;AAEtC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;IAEtB,QAAQ,CAAC,oBAAoB,EAAE;QAC7B,MAAM,MAAM,GAAG,iBAAY,CAAC,WAAI,CAAC,SAAS,EAAE,UAAU,CAAC,GAAG,UAAU,EAAE,MAAM,CAAC,CAAC;QAC9E,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;YAChE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;YAClF,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACxB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/test/index.ts b/test/index.ts deleted file mode 100644 index 190e667..0000000 --- a/test/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { readFileSync } from 'fs'; -import { join } from 'path'; - -/* eslint-env mocha */ -const assert = require('chai').assert; -const Parser = require('../').default; - -describe('Parser', () => { - - describe('JavaScript (Babel)', function () { - const source = readFileSync(join(__dirname, 'fixtures') + '/test.js', 'utf8'); - it('should return an object containing the parsed comments', () => { - const result = new Parser({ language: 'js' }).parse({ name: 'index.js', source }); - assert.isObject(result); - assert.isTrue(result.comments.length === 1); - }); - }); -}); diff --git a/tsconfig.json b/tsconfig.json index 0981fce..26a5c69 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,16 +1,16 @@ { "compilerOptions": { /* Basic Options */ - "target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ + "target": "es2016", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ // "lib": [], /* Specify library files to be included in the compilation: */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - // "declaration": true, /* Generates corresponding '.d.ts' file. */ - "sourceMap": true, /* Generates corresponding '.map' file. */ + "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ // "outFile": "./", /* Concatenate and emit output to single file. */ - // "outDir": "./", /* Redirect output structure to the directory. */ + "outDir": "./build/", /* Redirect output structure to the directory. */ // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ // "removeComments": true, /* Do not emit comments to output. */ // "noEmit": true, /* Do not emit outputs. */ @@ -20,11 +20,11 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ + "noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */ + "strictNullChecks": false, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + "noImplicitThis": false, /* Raise error on 'this' expressions with an implied 'any' type. */ + "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ /* Additional Checks */ // "noUnusedLocals": true, /* Report errors on unused locals. */ @@ -34,7 +34,7 @@ /* Module Resolution Options */ "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "baseUrl": ".", /* Base directory to resolve non-absolute module names. */ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ @@ -45,11 +45,11 @@ /* Source Map Options */ // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ /* Experimental Options */ - // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */, } } \ No newline at end of file