Repository: buehler/node-typescript-parser Branch: master Commit: 3ba4306f11bb Files: 137 Total size: 831.0 KB Directory structure: gitextract_bof42bjs/ ├── .appveyor.yml ├── .gitignore ├── .npmignore ├── .npmrc ├── .travis.yml ├── LICENSE ├── README.md ├── config/ │ ├── tsconfig.base.json │ └── tsconfig.build.json ├── jest.json ├── package.json ├── src/ │ ├── DeclarationIndex.ts │ ├── Node.ts │ ├── SymbolSpecifier.ts │ ├── TypescriptParser.ts │ ├── clonable/ │ │ └── Clonable.ts │ ├── code-generators/ │ │ ├── TypescriptCodeGenerator.ts │ │ ├── TypescriptGenerationOptions.ts │ │ └── typescript-generators/ │ │ ├── accessorDeclaration.ts │ │ ├── externalModuleImport.ts │ │ ├── methodDeclaration.ts │ │ ├── namedImport.ts │ │ ├── namespaceImport.ts │ │ ├── parameterDeclaration.ts │ │ ├── propertyDeclaration.ts │ │ ├── stringImport.ts │ │ ├── symbolSpecifier.ts │ │ └── variableDeclaration.ts │ ├── declarations/ │ │ ├── AccessorDeclaration.ts │ │ ├── ClassDeclaration.ts │ │ ├── ConstructorDeclaration.ts │ │ ├── Declaration.ts │ │ ├── DeclarationInfo.ts │ │ ├── DeclarationVisibility.ts │ │ ├── DefaultDeclaration.ts │ │ ├── EnumDeclaration.ts │ │ ├── FunctionDeclaration.ts │ │ ├── InterfaceDeclaration.ts │ │ ├── MethodDeclaration.ts │ │ ├── ModuleDeclaration.ts │ │ ├── ParameterDeclaration.ts │ │ ├── PropertyDeclaration.ts │ │ ├── TypeAliasDeclaration.ts │ │ ├── VariableDeclaration.ts │ │ └── index.ts │ ├── errors/ │ │ └── NotGeneratableYetError.ts │ ├── exports/ │ │ ├── AllExport.ts │ │ ├── AssignedExport.ts │ │ ├── Export.ts │ │ ├── NamedExport.ts │ │ └── index.ts │ ├── imports/ │ │ ├── ExternalModuleImport.ts │ │ ├── Import.ts │ │ ├── NamedImport.ts │ │ ├── NamespaceImport.ts │ │ ├── StringImport.ts │ │ └── index.ts │ ├── index.ts │ ├── node-parser/ │ │ ├── class-parser.ts │ │ ├── enum-parser.ts │ │ ├── export-parser.ts │ │ ├── function-parser.ts │ │ ├── identifier-parser.ts │ │ ├── import-parser.ts │ │ ├── index.ts │ │ ├── interface-parser.ts │ │ ├── module-parser.ts │ │ ├── parse-utilities.ts │ │ ├── traverse-ast.ts │ │ ├── type-alias-parser.ts │ │ └── variable-parser.ts │ ├── resources/ │ │ ├── File.ts │ │ ├── Module.ts │ │ ├── Namespace.ts │ │ ├── Resource.ts │ │ └── index.ts │ ├── type-guards/ │ │ ├── TypescriptGuards.ts │ │ └── TypescriptHeroGuards.ts │ └── utilities/ │ ├── PathHelpers.ts │ └── StringTemplate.ts ├── test/ │ ├── SpecificUsageCases.spec.ts │ ├── TypescriptParser.spec.ts │ ├── __snapshots__/ │ │ ├── SpecificUsageCases.spec.ts.snap │ │ └── TypescriptParser.spec.ts.snap │ ├── _workspace/ │ │ ├── .gitignore │ │ ├── declaration-index/ │ │ │ ├── _index.ts │ │ │ ├── another-classes.ts │ │ │ ├── circular-export/ │ │ │ │ ├── circularExport1.ts │ │ │ │ └── circularExport2.ts │ │ │ ├── classes.ts │ │ │ ├── exports/ │ │ │ │ ├── classes.ts │ │ │ │ ├── export-alias.ts │ │ │ │ ├── export-all.ts │ │ │ │ ├── export-from-export.ts │ │ │ │ └── export-some.ts │ │ │ ├── helper-functions.ts │ │ │ ├── index.ts │ │ │ ├── myReactTemplate.tsx │ │ │ ├── prototype-funcs.ts │ │ │ ├── reactFile.tsx │ │ │ └── specific-cases/ │ │ │ └── reindex-with-global-module-export/ │ │ │ └── classes.ts │ │ ├── specific-usage-cases/ │ │ │ ├── i18next-destructure/ │ │ │ │ ├── destructure-my-component.tsx │ │ │ │ └── import-my-component.tsx │ │ │ └── reexport/ │ │ │ ├── reexport-default.ts │ │ │ └── reexport-import.ts │ │ └── typescript-parser/ │ │ ├── async.ts │ │ ├── class.ts │ │ ├── enum.ts │ │ ├── exportsOnly.ts │ │ ├── function.ts │ │ ├── importsOnly.ts │ │ ├── interface.ts │ │ ├── javascript.js │ │ ├── jsx.jsx │ │ ├── module.ts │ │ ├── parameters.ts │ │ ├── specific-cases/ │ │ │ ├── 1.tsx │ │ │ ├── 2.tsx │ │ │ └── 3.tsx │ │ ├── typeAlias.ts │ │ ├── usagesOnly.ts │ │ ├── usagesOnly.tsx │ │ ├── variable.ts │ │ └── webpack-bundle.js │ ├── code-generators/ │ │ ├── TypescriptCodeGenerator.spec.ts │ │ └── __snapshots__/ │ │ └── TypescriptCodeGenerator.spec.ts.snap │ ├── declaration-index/ │ │ ├── DeclarationIndex.spec.ts │ │ ├── __snapshots__/ │ │ │ └── DeclarationIndex.spec.ts.snap │ │ └── specific-cases/ │ │ └── reindex-with-global-module/ │ │ ├── DeclarationIndex.reindex-with-global-module-export.spec.ts │ │ └── __snapshots__/ │ │ └── DeclarationIndex.reindex-with-global-module-export.spec.ts.snap │ ├── imports/ │ │ └── Imports.spec.ts │ ├── parsing/ │ │ ├── Flags.spec.ts │ │ └── __snapshots__/ │ │ └── Flags.spec.ts.snap │ ├── testUtilities.ts │ └── utilities/ │ └── PathHelpers.spec.ts ├── tsconfig.json └── tslint.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .appveyor.yml ================================================ version: "{build} - {branch}" skip_tags: true skip_branch_with_pr: true matrix: fast_finish: true environment: matrix: - nodejs_version: "10" install: - ps: Install-Product node $env:nodejs_version - npm install test_script: - npm test - npm install -g codecov - codecov - npm run build build: off ================================================ FILE: .gitignore ================================================ # node logs *.log npm-debug.log* node_modules/ # testing coverage/ # typescript build/ ================================================ FILE: .npmignore ================================================ # node logs *.log npm-debug.log* node_modules/ # testing coverage/ test/ # typescript src/ build/ tsconfig.json config/ tslint.json jest.json .travis.yml # docs docs/ ================================================ FILE: .npmrc ================================================ package-lock=false ================================================ FILE: .travis.yml ================================================ language: node_js stages: - name: test if: tag IS blank - name: build if: tag IS blank - name: deploy if: branch = master AND type != pull_request cache: directories: - node_modules matrix: fast_finish: true notifications: email: false jobs: include: - stage: test node_js: '10' after_success: - npm i -g codecov - codecov - stage: build node_js: '10' script: - npm run build - stage: deploy node_js: '10' script: npm run typedoc deploy: provider: pages skip_cleanup: true github_token: $GH_TOKEN local_dir: ./docs - stage: deploy node_js: '10' before_script: npm run build script: npm run semantic-release ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2017 TypeScript Heroes Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # node typescript parser This package is a TypeScript and ECMAScript parser. It uses the underlying typescript parser to generate a more or less human readable AST out of .js or .ts files. [![Build Status](https://travis-ci.org/buehler/node-typescript-parser.svg)](https://travis-ci.org/buehler/node-typescript-parser) [![Build Status Windows](https://ci.appveyor.com/api/projects/status/j06bqjc4tkdt7sej?svg=true)](https://ci.appveyor.com/project/buehler/node-typescript-parser) [![npm](https://img.shields.io/npm/v/typescript-parser.svg?maxAge=3600)](https://www.npmjs.com/package/typescript-parser) [![codecov](https://codecov.io/gh/buehler/node-typescript-parser/branch/master/graph/badge.svg)](https://codecov.io/gh/buehler/node-typescript-parser) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) [![Greenkeeper badge](https://badges.greenkeeper.io/buehler/node-typescript-parser.svg)](https://greenkeeper.io/) [![Gitter](https://img.shields.io/gitter/room/node-typescript-parser/Lobby.svg)](https://gitter.im/node-typescript-parser/Lobby) ## How to use After you install the package via: [![NPM](https://nodei.co/npm/typescript-parser.png?downloads=true&stars=true)](https://nodei.co/npm/typescript-parser/) ### [View Source Docs](https://buehler.github.io/node-typescript-parser/) You can use the parser with: ```typescript const parser = new TypescriptParser(); // either: const parsed = await parser.parseSource(/* typescript source code as string */); // or a filepath const parsed = await parser.parseFile('/user/myfile.ts', 'workspace root'); ``` You can also parse multiple files at ones. To use the declaration index (which is basically a list of symbols for your files) instantiate an index first and throw him some files. After the parsing is done, you'll get an index with resolved exports and declarations. Keep in mind, that the index'll only contain exported declarations. ## Changelog The changelog is generated by [semantic release](https://github.com/semantic-release/semantic-release) and is located under the [release section](https://github.com/buehler/node-typescript-parser/releases). ## Licence This software is licenced under the [MIT](LICENSE) licence. ================================================ FILE: config/tsconfig.base.json ================================================ { "compilerOptions": { "target": "es6", "module": "commonjs", "moduleResolution": "node", "removeComments": false, "outDir": "../build", "rootDir": "../src", "declaration": true, "sourceMap": false, "importHelpers": true, "strict": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, "noUnusedLocals": true, "noUnusedParameters": true, "lib": [ "es2015", "dom" ] }, "include": [ "../src/**/*" ], "exclude": [ "../node_modules", "../build" ] } ================================================ FILE: config/tsconfig.build.json ================================================ { "extends": "./tsconfig.base.json", "compilerOptions": { "outDir": "../" } } ================================================ FILE: jest.json ================================================ { "collectCoverage": true, "transform": { "^.+\\.tsx?$": "/node_modules/ts-jest/preprocessor.js" }, "testURL": "http://localhost/", "testMatch": [ "**/test/**/*.spec.ts" ], "testPathIgnorePatterns": [ "/node_modules/", "_workspace/" ], "moduleFileExtensions": [ "ts", "tsx", "js", "json" ] } ================================================ FILE: package.json ================================================ { "name": "typescript-parser", "version": "0.0.0-development", "description": "Parser for typescript (and javascript) files, that compiles those files and generates a human understandable AST.", "main": "index.js", "typings": "index.d.ts", "scripts": { "build": "npm run clean && tsc -p ./config/tsconfig.build.json", "clean": "del-cli ./build ./coverage", "develop": "npm run clean && tsc -p .", "lint": "tslint -c ./tslint.json -p ./config/tsconfig.build.json 'src/**/*.ts'", "test": "npm run lint && npm run clean && jest -c ./jest.json", "test:watch": "npm run clean && jest -c ./jest.json --watch --no-coverage", "typedoc": "del-cli ./docs && typedoc --ignoreCompilerErrors --out ./docs --mode file --tsconfig ./config/tsconfig.build.json ./src/", "semantic-release": "semantic-release" }, "repository": { "type": "git", "url": "https://github.com/TypeScript-Heroes/node-typescript-parser.git" }, "keywords": [ "typescript", "parser", "AST", "parsing" ], "author": "Christoph Bühler ", "license": "MIT", "bugs": { "url": "https://github.com/TypeScript-Heroes/node-typescript-parser/issues" }, "homepage": "https://github.com/TypeScript-Heroes/node-typescript-parser#readme", "devDependencies": { "@smartive/tslint-config": "^4.0.0", "@types/jest": "^23.3.1", "@types/lodash-es": "^4.17.1", "@types/mock-fs": "^3.6.30", "@types/node": "^10.9.4", "del-cli": "^1.1.0", "jest": "^23.5.0", "mock-fs": "^4.6.0", "semantic-release": "^15.9.12", "ts-jest": "^23.1.4", "tslint": "^5.11.0", "tsutils": "^3.0.0", "typedoc": "^0.12.0" }, "dependencies": { "lodash": "^4.17.10", "lodash-es": "^4.17.10", "tslib": "^1.9.3", "typescript": "^3.0.3" } } ================================================ FILE: src/DeclarationIndex.ts ================================================ import { difference, differenceWith, intersection, isEqual } from 'lodash'; import { join, normalize, relative, resolve } from 'path'; import { DeclarationInfo } from './declarations/DeclarationInfo'; import { ModuleDeclaration } from './declarations/ModuleDeclaration'; import { AllExport } from './exports/AllExport'; import { AssignedExport } from './exports/AssignedExport'; import { NamedExport } from './exports/NamedExport'; import { File } from './resources/File'; import { Module } from './resources/Module'; import { Namespace } from './resources/Namespace'; import { Resource } from './resources/Resource'; import { isExportableDeclaration } from './type-guards/TypescriptHeroGuards'; import { TypescriptParser } from './TypescriptParser'; import { normalizeFilename, normalizePathUri, toPosix } from './utilities/PathHelpers'; /** * Returns the name of the node folder. Is used as the library name for indexing. * (e.g. ./node_modules/webpack returns webpack) * * @param {string} path * @returns {string} */ function getNodeLibraryName(path: string): string { const dirs = path.split(/\/|\\/); const nodeIndex = dirs.indexOf('node_modules'); return normalizeFilename(dirs.slice(nodeIndex + 1).join('/')) .replace(new RegExp(`/(index|${dirs[nodeIndex + 1]}|${dirs[dirs.length - 2]})$`), ''); } /** * Helper type to index all possible resources of the current workspace. */ type Resources = { [name: string]: Resource }; /** * IndexDelta type, is calculated by the declaration index to give an overview, what has changed in the index. * Returns a list of deleted declarations, newly added declarations (with the corresponding infos) and * which declarations have been updated (with all declarations under that name). */ export type IndexDelta = { added: { [declaration: string]: DeclarationInfo[] }; updated: { [declaration: string]: DeclarationInfo[] }; deleted: string[]; }; /** * Interface for file changes. Contains lists of file uri's to the specific action. * * @export * @interface FileChanges */ export interface FileChanges { created: string[]; updated: string[]; deleted: string[]; } /** * Global index of declarations. Contains declarations and origins. * Provides reverse index for search and declaration info for imports. * * @export * @class DeclarationIndex */ export class DeclarationIndex { private building: boolean = false; /** * Hash of parsed resources. Contains all parsed files / namespaces / declarations * of the current workspace. * * @private * @type {Resources} * @memberof DeclarationIndex */ private parsedResources: Resources = Object.create(null); /** * Declaration index. Reverse index from a name to many declarations assotiated to the name. * * @private * @type {({ [declaration: string]: DeclarationInfo[] } | undefined)} * @memberof DeclarationIndex */ private _index: { [declaration: string]: DeclarationInfo[] } | undefined; /** * Indicator if the first index was loaded and calculated or not. * * @readonly * @type {boolean} * @memberof DeclarationIndex */ public get indexReady(): boolean { return this._index !== undefined; // && this._indexWithBarrels !== undefined; } /** * Reverse index of the declarations. * * @readonly * @type {({ [declaration: string]: DeclarationInfo[] } | undefined)} * @memberof DeclarationIndex */ public get index(): { [declaration: string]: DeclarationInfo[] } | undefined { return this._index; } /** * List of all declaration information. Contains the typescript declaration and the * "from" information (from where the symbol is imported). * * @readonly * @type {DeclarationInfo[]} * @memberof DeclarationIndex */ public get declarationInfos(): DeclarationInfo[] { return Object .keys(this.index!) .sort() .reduce((all, key) => all.concat(this.index![key]), []); } constructor(private parser: TypescriptParser, private rootPath: string) { } /** * Calculates the differences between two indices. Calculates removed, added and updated declarations. * The updated declarations are calculated and all declarations that the new index contains are inserted in the list. * * @static * @param {{ [declaration: string]: DeclarationInfo[] }} oldIndex * @param {{ [declaration: string]: DeclarationInfo[] }} newIndex * @returns {IndexDelta} * @memberof DeclarationIndex */ public static calculateIndexDelta( oldIndex: { [declaration: string]: DeclarationInfo[] }, newIndex: { [declaration: string]: DeclarationInfo[] }, ): IndexDelta { const oldKeys = Object.keys(oldIndex); const newKeys = Object.keys(newIndex); return { added: difference(newKeys, oldKeys).reduce( (obj, currentKey) => { obj[currentKey] = newIndex[currentKey]; return obj; }, {} as { [declaration: string]: DeclarationInfo[] }, ), updated: intersection(oldKeys, newKeys).reduce( (obj, currentKey) => { const old = oldIndex[currentKey]; const neu = newIndex[currentKey]; if (differenceWith(neu, old, isEqual).length > 0 || differenceWith(old, neu, isEqual).length > 0) { obj[currentKey] = neu; } return obj; }, {} as { [declaration: string]: DeclarationInfo[] }, ), deleted: difference(oldKeys, newKeys), }; } /** * Resets the whole index. Does delete everything. Period. * Is useful for unit testing or similar things. * * @memberof DeclarationIndex */ public reset(): void { this.parsedResources = Object.create(null); this._index = undefined; } /** * Tells the index to build a new index. * Can be canceled with a cancellationToken. * * @param {string[]} filePathes * @returns {Promise} * * @memberof DeclarationIndex */ public async buildIndex(filePathes: string[]): Promise { if (this.building) { return; } try { this.building = true; const parsed = await this.parser.parseFiles(filePathes, this.rootPath); this.parsedResources = await this.parseResources(parsed); this._index = await this.createIndex(this.parsedResources); } catch (e) { throw e; } finally { this.building = false; } } /** * Is called when file events happen. Does reindex for the changed files and creates a new index. * Returns the differences for the new index. * * @param {FileEvent[]} changes * @returns {Promise} * * @memberof DeclarationIndex */ public async reindexForChanges(changes: FileChanges): Promise { const rebuildResources: string[] = []; const removeResources: string[] = []; const rebuildFiles: string[] = []; for (const change of changes.deleted) { const filePath = normalizePathUri(change); const resource = '/' + normalizeFilename(relative(this.rootPath, filePath)); if (removeResources.indexOf(resource) < 0) { removeResources.push(resource); } for (const file of this.getExportedResources(resource)) { if (rebuildFiles.indexOf(file) < 0) { rebuildFiles.push(file); } } } for (const change of (changes.created || []).concat(changes.updated)) { const filePath = normalizePathUri(change); const resource = '/' + normalizeFilename(relative(this.rootPath, filePath)); if (rebuildResources.indexOf(resource) < 0) { rebuildResources.push(resource); } if (rebuildFiles.indexOf(filePath) < 0) { rebuildFiles.push(filePath); } for (const file of this.getExportedResources(resource)) { if (rebuildFiles.indexOf(file) < 0) { rebuildFiles.push(file); } } } const resources = await this.parseResources( await this.parser.parseFiles(rebuildFiles, this.rootPath), ); for (const del of removeResources) { delete this.parsedResources[del]; } for (const key of Object.keys(resources)) { this.parsedResources[key] = resources[key]; } const old = this._index || {}; this._index = await this.createIndex(this.parsedResources); return DeclarationIndex.calculateIndexDelta(old, this._index); } /** * Returns a list of files that export a certain resource (declaration). * * @private * @param {string} resourceToCheck * @returns {string[]} * * @memberof DeclarationIndex */ private getExportedResources(resourceToCheck: string): string[] { const resources: string[] = []; Object .keys(this.parsedResources) .forEach((key) => { const resource = this.parsedResources[key]; if (resource instanceof File && this.doesExportResource(resource, resourceToCheck)) { resources.push(resource.filePath); } }); return resources; } /** * Checks if a file does export another resource. * (i.e. export ... from ...) * * @private * @param {File} resource The file that is checked * @param {string} resourcePath The resource that is searched for * @returns {boolean} * * @memberof DeclarationIndex */ private doesExportResource(resource: File, resourcePath: string): boolean { let exportsResource = false; for (const ex of resource.exports) { if (exportsResource) { break; } if (ex instanceof AllExport || ex instanceof NamedExport) { const exported = '/' + toPosix(relative(this.rootPath, normalize(join(resource.parsedPath.dir, ex.from)))); exportsResource = exported === resourcePath; } } return exportsResource; } /** * Does parse the resources (symbols and declarations) of a given file. * Can be cancelled with the token. * * @private * @param {File[]} [files=[]] * @returns {Promise} * * @memberof DeclarationIndex */ private async parseResources(files: File[] = []): Promise { const parsedResources: Resources = Object.create(null); for (const file of files) { if (file.filePath.indexOf('typings') > -1 || file.filePath.indexOf('node_modules/@types') > -1) { for (const resource of file.resources) { parsedResources[resource.identifier] = resource; } } else if (file.filePath.indexOf('node_modules') > -1) { const libname = getNodeLibraryName(file.filePath); parsedResources[libname] = file; } else { parsedResources[file.identifier] = file; } } for (const key of Object.keys(parsedResources).sort((k1, k2) => k2.length - k1.length)) { const resource = parsedResources[key]; resource.declarations = resource.declarations.filter( o => isExportableDeclaration(o) && o.isExported, ); this.processResourceExports(parsedResources, resource); } return parsedResources; } /** * Creates a reverse index out of the give resources. * Can be cancelled with the token. * * @private * @param {Resources} resources * @returns {Promise} * * @memberof DeclarationIndex */ private async createIndex(resources: Resources): Promise<{ [declaration: string]: DeclarationInfo[] }> { // Use an empty object without a prototype, so that "toString" (for example) can be indexed // Thanks to @gund in https://github.com/buehler/typescript-hero/issues/79 const index: { [declaration: string]: DeclarationInfo[] } = Object.create(null); for (const key of Object.keys(resources)) { const resource = resources[key]; if (resource instanceof Namespace || resource instanceof Module) { if (!index[resource.name]) { index[resource.name] = []; } index[resource.name].push(new DeclarationInfo( new ModuleDeclaration(resource.getNamespaceAlias(), resource.start, resource.end), resource.name, )); } for (const declaration of resource.declarations) { if (!index[declaration.name]) { index[declaration.name] = []; } const from = key.replace(/\/index$/, '') || '/'; if (!index[declaration.name].some( o => o.declaration.constructor === declaration.constructor && o.from === from, )) { index[declaration.name].push(new DeclarationInfo(declaration, from)); } } } return index; } /** * Process all exports of a the parsed resources. Does move the declarations accordingly to their * export nature. * * @private * @param {Resources} parsedResources * @param {Resource} resource * @param {Resource[]} [processedResources=[]] * @returns {void} * * @memberof DeclarationIndex */ private processResourceExports( parsedResources: Resources, resource: Resource, processedResources: Resource[] = [], ): void { if (processedResources.indexOf(resource) >= 0 || resource.exports.length === 0) { return; } processedResources.push(resource); for (const ex of resource.exports) { if (resource instanceof File && (ex instanceof NamedExport || ex instanceof AllExport)) { if (!ex.from) { return; } let sourceLib = resolve(resource.parsedPath.dir, ex.from); if (sourceLib.indexOf('node_modules') > -1) { sourceLib = getNodeLibraryName(sourceLib); } else { sourceLib = '/' + normalizeFilename(relative(this.rootPath, sourceLib)); } if (!parsedResources[sourceLib]) { return; } const exportedLib = parsedResources[sourceLib]; this.processResourceExports(parsedResources, exportedLib, processedResources); if (ex instanceof AllExport) { this.processAllFromExport(resource, exportedLib); } else { this.processNamedFromExport(ex, resource, exportedLib); } } else { if (ex instanceof AssignedExport) { for (const lib of ex.exported.filter(o => !isExportableDeclaration(o))) { this.processResourceExports(parsedResources, lib as Resource, processedResources); } this.processAssignedExport(ex, resource); } else if (ex instanceof NamedExport && ex.from && parsedResources[ex.from]) { this.processResourceExports( parsedResources, parsedResources[ex.from], processedResources, ); this.processNamedFromExport(ex, resource, parsedResources[ex.from]); } } } } /** * Processes an all export, does move the declarations accordingly. * (i.e. export * from './myFile') * * @private * @param {Resource} exportingLib * @param {Resource} exportedLib * * @memberof DeclarationIndex */ private processAllFromExport(exportingLib: Resource, exportedLib: Resource): void { exportingLib.declarations.push(...exportedLib.declarations); exportedLib.declarations = []; } /** * Processes a named export, does move the declarations accordingly. * (i.e. export {MyClass} from './myFile') * * @private * @param {NamedExport} tsExport * @param {Resource} exportingLib * @param {Resource} exportedLib * * @memberof DeclarationIndex */ private processNamedFromExport( tsExport: NamedExport, exportingLib: Resource, exportedLib: Resource, ): void { exportedLib.declarations .forEach((o) => { if (!tsExport.specifiers) { return; } const ex = tsExport.specifiers.find(s => s.specifier === o.name); if (!ex) { return; } exportedLib.declarations.splice(exportedLib.declarations.indexOf(o), 1); if (ex.alias) { o.name = ex.alias; } exportingLib.declarations.push(o); }); } /** * Processes an assigned export, does move the declarations accordingly. * (i.e. export = namespaceName) * * @private * @param {AssignedExport} tsExport * @param {Resource} exportingLib * * @memberof DeclarationIndex */ private processAssignedExport( tsExport: AssignedExport, exportingLib: Resource, ): void { tsExport.exported.forEach((exported) => { if (isExportableDeclaration(exported)) { exportingLib.declarations.push(exported); } else { exportingLib.declarations.push( ...exported.declarations.filter( o => isExportableDeclaration(o) && o.isExported, ), ); exported.declarations = []; } }); } } ================================================ FILE: src/Node.ts ================================================ /** * Base class for all nodes / declarations / imports / etc. in the extension. * Contains basic information about the node. * * @export * @interface Node */ export interface Node { /** * The starting character of the node in the document. * * @type {number} * @memberof Node */ start?: number; /** * The ending character of the node in the document. * * @type {number} * @memberof Node */ end?: number; } ================================================ FILE: src/SymbolSpecifier.ts ================================================ import { Clonable } from './clonable/Clonable'; /** * Class for symbols that are contained in a named import or export or anywhere. Basically an aliased object. * (i.e. import {SYMBOL} from '...'). * * @export * @class SymbolSpecifier * @implements {Clonable} */ export class SymbolSpecifier implements Clonable { constructor(public specifier: string, public alias?: string) { } /** * Clones the current resolve specifier and returns a new instance with the same properties. * * @returns {SymbolSpecifier} * * @memberof SymbolSpecifier */ public clone(): SymbolSpecifier { return new SymbolSpecifier(this.specifier, this.alias); } } ================================================ FILE: src/TypescriptParser.ts ================================================ import { readFileSync } from 'fs'; import { parse } from 'path'; import { ClassDeclaration, createSourceFile, EnumDeclaration, ExportAssignment, ExportDeclaration, FunctionDeclaration, Identifier, ImportDeclaration, ImportEqualsDeclaration, InterfaceDeclaration, ModuleDeclaration, Node, ScriptKind, ScriptTarget, SourceFile, SyntaxKind, TypeAliasDeclaration, VariableStatement, } from 'typescript'; import { parseClass } from './node-parser/class-parser'; import { parseEnum } from './node-parser/enum-parser'; import { parseExport } from './node-parser/export-parser'; import { parseFunction } from './node-parser/function-parser'; import { parseIdentifier } from './node-parser/identifier-parser'; import { parseImport } from './node-parser/import-parser'; import { parseInterface } from './node-parser/interface-parser'; import { parseModule } from './node-parser/module-parser'; import { traverseAst } from './node-parser/traverse-ast'; import { parseTypeAlias } from './node-parser/type-alias-parser'; import { parseVariable } from './node-parser/variable-parser'; import { File } from './resources/File'; import { Resource } from './resources/Resource'; /** * Magic.happens('here'); * This class is the parser of the whole extension. It uses the typescript compiler to parse a file or given * source code into the token stream and therefore into the AST of the source. Afterwards an array of * resources is generated and returned. * * @export * @class TypescriptParser */ export class TypescriptParser { /** * Parses the given source into an anonymous File resource. * Mainly used to parse source code of a document. * * @param {string} source * @param {ScriptKind} [scriptKind=ScriptKind.TS] * @returns {Promise} * * @memberof TsResourceParser */ public async parseSource(source: string, scriptKind: ScriptKind = ScriptKind.TS): Promise { return await this.parseTypescript( createSourceFile( 'inline.tsx', source, ScriptTarget.ES2015, true, scriptKind), '/'); } /** * Parses a single file into a parsed file. * * @param {string} filePath * @param {string} rootPath * @returns {Promise} * * @memberof TsResourceParser */ public async parseFile(filePath: string, rootPath: string): Promise { const parse = await this.parseFiles([filePath], rootPath); return parse[0]; } /** * Parses multiple files into parsed files. * * @param {string[]} filePathes * @param {string} rootPath * @returns {Promise} * * @memberof TsResourceParser */ public async parseFiles( filePathes: string[], rootPath: string): Promise { return filePathes .map((o) => { let scriptKind: ScriptKind = ScriptKind.Unknown; const parsed = parse(o); switch (parsed.ext.toLowerCase()) { case 'js': scriptKind = ScriptKind.JS; break; case 'jsx': scriptKind = ScriptKind.JSX; break; case 'ts': scriptKind = ScriptKind.TS; break; case 'tsx': scriptKind = ScriptKind.TSX; break; } return createSourceFile( o, readFileSync(o).toString(), ScriptTarget.ES2015, true, scriptKind, ); }) .map(o => this.parseTypescript(o, rootPath)); } /** * Parses the typescript source into the file instance. Calls .parse afterwards to * get the declarations and other information about the source. * * @private * @param {SourceFile} source * @param {string} rootPath * @returns {TsFile} * * @memberof TsResourceParser */ private parseTypescript(source: SourceFile, rootPath: string): File { const file = new File(source.fileName, rootPath, source.getStart(), source.getEnd()); const syntaxList = source.getChildAt(0); this.parse(file, syntaxList); return file; } /** * Recursive function that runs through the AST of a source and parses the nodes. * Creates the class / function / etc declarations and instanciates a new module / namespace * resource if needed. * * @private * @param {Resource} resource * @param {Node} node * * @memberof TsResourceParser */ private parse(resource: Resource, root: Node): void { const modules = [{ moduleRoot: root, moduleResource: resource }]; for (let iter = modules.shift(); iter !== undefined; iter = modules.shift()) { const { moduleRoot, moduleResource } = iter; traverseAst( moduleRoot as any, (node: any) => { switch (node.kind) { case SyntaxKind.ImportDeclaration: case SyntaxKind.ImportEqualsDeclaration: parseImport(moduleResource, node); break; case SyntaxKind.ExportDeclaration: case SyntaxKind.ExportAssignment: parseExport(moduleResource, node); break; case SyntaxKind.EnumDeclaration: parseEnum(moduleResource, node); break; case SyntaxKind.TypeAliasDeclaration: parseTypeAlias(moduleResource, node); break; case SyntaxKind.FunctionDeclaration: parseFunction(moduleResource, node); break; case SyntaxKind.VariableStatement: parseVariable(moduleResource, node); break; case SyntaxKind.InterfaceDeclaration: parseInterface(moduleResource, node); break; case SyntaxKind.ClassDeclaration: parseClass(moduleResource, node); break; case SyntaxKind.Identifier: parseIdentifier(moduleResource, node); break; case SyntaxKind.ModuleDeclaration: modules.push({ moduleRoot: node, moduleResource: parseModule(moduleResource, node), }); break; default: break; } }, (node: any) => { switch (node.kind) { case SyntaxKind.ClassDeclaration: case SyntaxKind.ModuleDeclaration: case SyntaxKind.FunctionDeclaration: return true; default: return false; } }, ); } } } ================================================ FILE: src/clonable/Clonable.ts ================================================ /** * Interface for clonable objects. The clone() method creates a deep clone of the object. * * @export * @template T * @interface Clonable */ export interface Clonable { /** * Create a deep clone of this object. * * @returns {T} * * @memberof Clonable */ clone(): T; } ================================================ FILE: src/code-generators/TypescriptCodeGenerator.ts ================================================ import { GetterDeclaration, SetterDeclaration } from '../declarations/AccessorDeclaration'; import { Declaration } from '../declarations/Declaration'; import { MethodDeclaration } from '../declarations/MethodDeclaration'; import { ParameterDeclaration } from '../declarations/ParameterDeclaration'; import { PropertyDeclaration } from '../declarations/PropertyDeclaration'; import { VariableDeclaration } from '../declarations/VariableDeclaration'; import { NotGeneratableYetError } from '../errors/NotGeneratableYetError'; import { Export } from '../exports/Export'; import { ExternalModuleImport } from '../imports/ExternalModuleImport'; import { Import } from '../imports/Import'; import { NamedImport } from '../imports/NamedImport'; import { NamespaceImport } from '../imports/NamespaceImport'; import { StringImport } from '../imports/StringImport'; import { SymbolSpecifier } from '../SymbolSpecifier'; import { generateAccessorDeclaration } from './typescript-generators/accessorDeclaration'; import { generateExternalModuleImport } from './typescript-generators/externalModuleImport'; import { generateMethodDeclaration } from './typescript-generators/methodDeclaration'; import { generateNamedImport } from './typescript-generators/namedImport'; import { generateNamespaceImport } from './typescript-generators/namespaceImport'; import { generateParameterDeclaration } from './typescript-generators/parameterDeclaration'; import { generatePropertyDeclaration } from './typescript-generators/propertyDeclaration'; import { generateStringImport } from './typescript-generators/stringImport'; import { generateSymbolSpecifier } from './typescript-generators/symbolSpecifier'; import { generateVariableDelcaration } from './typescript-generators/variableDeclaration'; import { TypescriptGenerationOptions } from './TypescriptGenerationOptions'; /** * All generatable items combined. If the element is not generatable, the specific generator should throw * an exception. */ export type Generatable = Declaration | Import | Export | SymbolSpecifier; /** * Type for generators. */ export type Generators = { [name: string]: (generatable: Generatable, options: TypescriptGenerationOptions) => string }; /** * Hash with all possible (yet implemented) generators. */ export const GENERATORS: Generators = { [SymbolSpecifier.name]: generateSymbolSpecifier as any, [MethodDeclaration.name]: generateMethodDeclaration, [ParameterDeclaration.name]: generateParameterDeclaration, [PropertyDeclaration.name]: generatePropertyDeclaration, [VariableDeclaration.name]: generateVariableDelcaration, [ExternalModuleImport.name]: generateExternalModuleImport, [NamedImport.name]: generateNamedImport, [NamespaceImport.name]: generateNamespaceImport, [StringImport.name]: generateStringImport, [SetterDeclaration.name]: generateAccessorDeclaration, [GetterDeclaration.name]: generateAccessorDeclaration, }; /** * Generator for typescript code elements. Takes a generatable object and tries to generate typescript code. * * @export * @class TypescriptCodeGenerator */ export class TypescriptCodeGenerator { constructor(private options: TypescriptGenerationOptions) { } /** * Generator function. Calls the specific element generator. If no generator is found, an exception is thrown. * * @param {Generatable} declaration * @returns {string} * @throws {NotGeneratableYetError} * @memberof TypescriptCodeGenerator */ public generate(declaration: Generatable): string { if (GENERATORS[declaration.constructor.name]) { return GENERATORS[declaration.constructor.name](declaration, this.options); } throw new NotGeneratableYetError(declaration); } } ================================================ FILE: src/code-generators/TypescriptGenerationOptions.ts ================================================ export enum MultiLineImportRule { strictlyOneImportPerLine = 'strictlyOneImportPerLine', oneImportPerLineOnlyAfterThreshold = 'oneImportPerLineOnlyAfterThreshold', multipleImportsPerLine = 'multipleImportsPerLine', } /** * Typescript generation options type. Contains all information needed to stringify some objects to typescript. * * @export * @interface TypescriptGenerationOptions */ export interface TypescriptGenerationOptions { /** * Which quote type should be used (' or "). * * @type {string} * @memberof TypescriptGenerationOptions */ stringQuoteStyle: string; /** * Defines end of line character (semicolon or nothing). * * @type {('' | ';')} * @memberof TypescriptGenerationOptions */ eol: '' | ';'; /** * Defines if the symbols should have spacing in the braces ({ Foo } or {Foo}). * * @type {boolean} * @memberof TypescriptGenerationOptions */ spaceBraces: boolean; /** * The wrapping methodology to be used for imports. * * @type {MultiLineImportRule} * @memberof TypescriptGenerationOptions */ wrapMethod: MultiLineImportRule; /** * The threshold where an import is written as multiline. * * @type {number} * @memberof TypescriptGenerationOptions */ multiLineWrapThreshold: number; /** * Defines if the last line of a multiline import should have a comma. * * @type {boolean} * @memberof TypescriptGenerationOptions */ multiLineTrailingComma: boolean; /** * How many spaces of indentiation. * * @type {number} * @memberof TypescriptGenerationOptions */ tabSize: number; /** * Insert spaces instead of tabs (default: true) * * @type {boolean} * @memberof TypescriptGenerationOptions */ insertSpaces: boolean; } ================================================ FILE: src/code-generators/typescript-generators/accessorDeclaration.ts ================================================ import { AccessorDeclaration, SetterDeclaration } from '../../declarations/AccessorDeclaration'; import { getVisibilityText } from '../../declarations/DeclarationVisibility'; import { TypescriptGenerationOptions } from '../TypescriptGenerationOptions'; /** * Generates typescript code for a class property accessor. * * @export * @param {AccessorDeclaration} accessor * @param {TypescriptGenerationOptions} { tabSize } * @returns {string} */ export function generateAccessorDeclaration( accessor: AccessorDeclaration, { tabSize }: TypescriptGenerationOptions, ): string { const tabs = Array(tabSize + 1).join(' '); let definitionLine: string; if (accessor instanceof SetterDeclaration) { definitionLine = `${tabs}${accessor.visibility !== undefined ? getVisibilityText(accessor.visibility) + ' ' : ''}` + `${accessor.isAbstract ? 'abstract ' : ''}` + `set ${accessor.name}(value${accessor.type ? `: ${accessor.type}` : ''})`; } else { definitionLine = `${tabs}${accessor.visibility !== undefined ? getVisibilityText(accessor.visibility) + ' ' : ''}` + `${accessor.isAbstract ? 'abstract ' : ''}` + `get ${accessor.name}()${accessor.type ? `: ${accessor.type}` : ''}`; } if (accessor.isAbstract) { return `${definitionLine};`; } return `${definitionLine} { ${tabs}${tabs}throw new Error('Not implemented yet.'); ${tabs}}\n`; } ================================================ FILE: src/code-generators/typescript-generators/externalModuleImport.ts ================================================ import { ExternalModuleImport } from '../../imports/ExternalModuleImport'; import { TypescriptGenerationOptions } from '../TypescriptGenerationOptions'; /** * Generates typescript code for an external module import. * * @export * @param {ExternalModuleImport} imp * @param {TypescriptGenerationOptions} { stringQuoteStyle, eol } * @returns {string} */ export function generateExternalModuleImport( imp: ExternalModuleImport, { stringQuoteStyle, eol }: TypescriptGenerationOptions, ): string { return `import ${imp.alias} = require(${stringQuoteStyle}${imp.libraryName}${stringQuoteStyle})${eol}`; } ================================================ FILE: src/code-generators/typescript-generators/methodDeclaration.ts ================================================ import { getVisibilityText } from '../../declarations/DeclarationVisibility'; import { MethodDeclaration } from '../../declarations/MethodDeclaration'; import { TypescriptGenerationOptions } from '../TypescriptGenerationOptions'; import { generateParameterDeclaration } from './parameterDeclaration'; /** * Generates typescript code for a method declaration. * * @export * @param {MethodDeclaration} method * @param {TypescriptGenerationOptions} { tabSize } * @returns {string} */ export function generateMethodDeclaration(method: MethodDeclaration, { tabSize }: TypescriptGenerationOptions): string { const intend = Array(tabSize + 1).join(' '); return `${intend}` + `${method.visibility !== undefined ? getVisibilityText(method.visibility) + ' ' : ''}${method.name}(` + `${method.parameters.map(o => generateParameterDeclaration(o)).join(', ')})` + `${method.type ? `: ${method.type}` : ''} { ${intend}${intend}throw new Error('Not implemented yet.'); ${intend}}\n`; } ================================================ FILE: src/code-generators/typescript-generators/namedImport.ts ================================================ import { NamedImport } from '../../imports/NamedImport'; import { SymbolSpecifier } from '../../SymbolSpecifier'; import { stringTemplate } from '../../utilities/StringTemplate'; import { MultiLineImportRule, TypescriptGenerationOptions } from '../TypescriptGenerationOptions'; import { generateSymbolSpecifier } from './symbolSpecifier'; const oneLinerImportTemplate = stringTemplate`import ${0} from ${1}`; const multiLineImportTemplate = stringTemplate`import ${3}{ ${0}${1} } from ${2}`; const defaultAliasOnlyMultiLineImportTemplate = stringTemplate`import ${0} from ${1}`; /** * Sort function for symbol specifiers. Does sort after the specifiers name (to lowercase). * * @param {SymbolSpecifier} i1 * @param {SymbolSpecifier} i2 * @returns {number} */ function specifierSort(i1: SymbolSpecifier, i2: SymbolSpecifier): number { const strA = i1.specifier.toLowerCase(); const strB = i2.specifier.toLowerCase(); if (strA < strB) { return -1; } if (strA > strB) { return 1; } return 0; } /** * Generates typescript code for a named import. * * @export * @param {NamedImport} imp * @param {TypescriptGenerationOptions} { stringQuoteStyle, eol } * @returns {string} */ export function generateNamedImport( imp: NamedImport, { eol, stringQuoteStyle, spaceBraces, tabSize, wrapMethod, multiLineWrapThreshold, multiLineTrailingComma, insertSpaces = true, }: TypescriptGenerationOptions, ): string { const lib = `${stringQuoteStyle}${imp.libraryName}${stringQuoteStyle}${eol}`; // const specifiers = imp.specifiers.sort(specifierSort).map(o => generateSymbolSpecifier(o)).join(', '); const oneLinerImportStatement = oneLinerImportTemplate(getImportSpecifiers(imp, spaceBraces), lib); if (oneLinerImportStatement.length <= multiLineWrapThreshold && (wrapMethod !== MultiLineImportRule.strictlyOneImportPerLine || imp.specifiers.length <= 1)) { return oneLinerImportStatement; } const defaultAliasOnly: boolean = imp.specifiers.length === 0; if (defaultAliasOnly) { return defaultAliasOnlyMultiLineImportTemplate( imp.defaultAlias ? `${imp.defaultAlias}, ` : '', `${stringQuoteStyle}${imp.libraryName}${stringQuoteStyle}${eol}`, ); } const sortedImportSpecifiers: SymbolSpecifier[] = imp.specifiers.sort(specifierSort); let importSpecifierStrings: string = ''; const indent = insertSpaces ? Array(tabSize + 1).join(' ') : '\t'; if (wrapMethod === MultiLineImportRule.strictlyOneImportPerLine || wrapMethod === MultiLineImportRule.oneImportPerLineOnlyAfterThreshold) { importSpecifierStrings = sortedImportSpecifiers.map(o => `${indent}${generateSymbolSpecifier(o)}`).join(',\n'); } else if (wrapMethod === MultiLineImportRule.multipleImportsPerLine) { importSpecifierStrings = sortedImportSpecifiers.reduce( (acc, curr) => { const symbolSpecifier: string = generateSymbolSpecifier(curr); // const dist: number = acc.out.length - acc.lastWrapOffset + symbolSpecifier.length; const importLines = acc.out.split('\n'); const lastImportLine = importLines[importLines.length - 1]; const dist: number = lastImportLine.length + `, `.length + symbolSpecifier.length; const needsWrap: boolean = dist >= multiLineWrapThreshold; return { out: acc.out + (needsWrap ? `,\n${indent}` : (acc.out.length ? `, ` : `${indent}`)) + symbolSpecifier, lastWrapOffset: acc.lastWrapOffset + (needsWrap ? dist : 0), }; }, { out: '', lastWrapOffset: 0, }, ).out; } return multiLineImportTemplate( importSpecifierStrings, multiLineTrailingComma ? ',' : '', `${stringQuoteStyle}${imp.libraryName}${stringQuoteStyle}${eol}`, imp.defaultAlias ? `${imp.defaultAlias}, ` : '', ); } function getImportSpecifiers(namedImport: NamedImport, spaceBraces: boolean): string { if (namedImport.defaultAlias && namedImport.specifiers.length <= 0) { return namedImport.defaultAlias; } const space = spaceBraces ? ' ' : ''; const specifiers = namedImport.specifiers.sort(specifierSort).map(o => generateSymbolSpecifier(o)).join(', '); let importSpecifiers = `${space}${specifiers}${space}`; if (importSpecifiers.trim().length === 0) { importSpecifiers = ' '; } if (namedImport.defaultAlias && namedImport.specifiers.length > 0) { return `${namedImport.defaultAlias}, {${importSpecifiers}}`; } return `{${importSpecifiers}}`; } ================================================ FILE: src/code-generators/typescript-generators/namespaceImport.ts ================================================ import { NamespaceImport } from '../../imports/NamespaceImport'; import { TypescriptGenerationOptions } from '../TypescriptGenerationOptions'; /** * Generates typescript code for a namespace import * * @export * @param {NamespaceImport} imp * @param {TypescriptGenerationOptions} { stringQuoteStyle, eol } * @returns {string} */ export function generateNamespaceImport( imp: NamespaceImport, { stringQuoteStyle, eol }: TypescriptGenerationOptions, ): string { return `import * as ${imp.alias} from ${stringQuoteStyle}${imp.libraryName}${stringQuoteStyle}${eol}`; } ================================================ FILE: src/code-generators/typescript-generators/parameterDeclaration.ts ================================================ import { ParameterDeclaration } from '../../declarations/ParameterDeclaration'; /** * Generates typescript code for parameters. * * @export * @param {ParameterDeclaration} parameter * @returns {string} */ export function generateParameterDeclaration(parameter: ParameterDeclaration): string { return `${parameter.name}${parameter.type ? `: ${parameter.type}` : ''}`; } ================================================ FILE: src/code-generators/typescript-generators/propertyDeclaration.ts ================================================ import { getVisibilityText } from '../../declarations/DeclarationVisibility'; import { PropertyDeclaration } from '../../declarations/PropertyDeclaration'; import { TypescriptGenerationOptions } from '../TypescriptGenerationOptions'; /** * Generates typescript code for a class property. * * @export * @param {PropertyDeclaration} property * @param {TypescriptGenerationOptions} { tabSize } * @returns {string} */ export function generatePropertyDeclaration( property: PropertyDeclaration, { tabSize }: TypescriptGenerationOptions, ): string { return `${Array(tabSize + 1).join(' ')}` + `${property.visibility !== undefined ? getVisibilityText(property.visibility) + ' ' : ''}` + `${property.name}${property.isOptional ? '?' : ''}${property.type ? `: ${property.type}` : ''};\n`; } ================================================ FILE: src/code-generators/typescript-generators/stringImport.ts ================================================ import { StringImport } from '../../imports/StringImport'; import { TypescriptGenerationOptions } from '../TypescriptGenerationOptions'; /** * Generates typescript code for a string import. * * @export * @param {StringImport} imp * @param {TypescriptGenerationOptions} { stringQuoteStyle, eol } * @returns {string} */ export function generateStringImport(imp: StringImport, { stringQuoteStyle, eol }: TypescriptGenerationOptions): string { return `import ${stringQuoteStyle}${imp.libraryName}${stringQuoteStyle}${eol}`; } ================================================ FILE: src/code-generators/typescript-generators/symbolSpecifier.ts ================================================ import { SymbolSpecifier } from '../../SymbolSpecifier'; /** * Generates typescript code for a symbol specifier. * * @export * @param {SymbolSpecifier} specifier * @returns {string} */ export function generateSymbolSpecifier(specifier: SymbolSpecifier): string { return `${specifier.specifier}${specifier.alias ? ` as ${specifier.alias}` : ''}`; } ================================================ FILE: src/code-generators/typescript-generators/variableDeclaration.ts ================================================ import { VariableDeclaration } from '../../declarations/VariableDeclaration'; /** * Generates typescript code for a variable. * * @export * @param {VariableDelcaration} variable * @returns {string} */ export function generateVariableDelcaration(variable: VariableDeclaration): string { return `${variable.name}${variable.type ? `: ${variable.type}` : ''}`; } ================================================ FILE: src/declarations/AccessorDeclaration.ts ================================================ import { AbstractDeclaration, ScopedDeclaration, StaticDeclaration, TypedDeclaration } from './Declaration'; import { DeclarationVisibility } from './DeclarationVisibility'; /** * Property accessor declaration. This element represents the base and will be used in setters and getters. * * @export * @abstract * @class AccessorDeclaration * @implements {ScopedDeclaration} * @implements {TypedDeclaration} * @implements {AbstractDeclaration} */ export abstract class AccessorDeclaration implements ScopedDeclaration, StaticDeclaration, TypedDeclaration, AbstractDeclaration { constructor( public name: string, public visibility: DeclarationVisibility | undefined, public type: string | undefined, public isAbstract: boolean, public isStatic: boolean, public start?: number, public end?: number, ) { } } /** * Getter declaration for a getter accessor of a class property. * * @export * @class GetterDeclaration * @extends {AccessorDeclaration} */ export class GetterDeclaration extends AccessorDeclaration { } /** * Setter declaration for a getter accessor of a class property. * * @export * @class SetterDeclaration * @extends {AccessorDeclaration} */ export class SetterDeclaration extends AccessorDeclaration { } ================================================ FILE: src/declarations/ClassDeclaration.ts ================================================ import { AccessorDeclaration } from './AccessorDeclaration'; import { ConstructorDeclaration } from './ConstructorDeclaration'; import { ClassLikeDeclaration, ExportableDeclaration, GenericDeclaration } from './Declaration'; import { MethodDeclaration } from './MethodDeclaration'; import { PropertyDeclaration } from './PropertyDeclaration'; /** * Class declaration that contains methods, properties and a constructor * * @export * @class ClassDeclaration * @implements {ClassLikeDeclaration} * @implements {ExportableDeclaration} * @implements {GenericDeclaration} */ export class ClassDeclaration implements ClassLikeDeclaration, ExportableDeclaration, GenericDeclaration { public ctor: ConstructorDeclaration | undefined; public accessors: AccessorDeclaration[] = []; public properties: PropertyDeclaration[] = []; public methods: MethodDeclaration[] = []; public typeParameters: string[] | undefined; constructor( public name: string, public isExported: boolean, public start?: number, public end?: number, ) { } } ================================================ FILE: src/declarations/ConstructorDeclaration.ts ================================================ import { CallableDeclaration } from './Declaration'; import { ParameterDeclaration } from './ParameterDeclaration'; import { VariableDeclaration } from './VariableDeclaration'; /** * Constructor declaration that is contained in a class. * * @export * @class ConstructorDeclaration * @implements {CallableDeclaration} */ export class ConstructorDeclaration implements CallableDeclaration { public parameters: ParameterDeclaration[] = []; public variables: VariableDeclaration[] = []; constructor( public name: string, public start?: number, public end?: number, ) { } } ================================================ FILE: src/declarations/Declaration.ts ================================================ import { Node } from '../Node'; import { AccessorDeclaration } from './AccessorDeclaration'; import { DeclarationVisibility } from './DeclarationVisibility'; import { MethodDeclaration } from './MethodDeclaration'; import { ParameterDeclaration } from './ParameterDeclaration'; import { PropertyDeclaration } from './PropertyDeclaration'; import { VariableDeclaration } from './VariableDeclaration'; /** * Basic interface for all declarations. Defines the basic needed information for a typescript declaration. * * @export * @interface Declaration * @extends {Node} */ export interface Declaration extends Node { /** * The name of the declaration. * * @type {string} * @memberof Declaration */ name: string; } /** * Interface for all typed declarations. Those declarations contain a type that must be taken care of. * (e.g. 'string' or 'number') * * @export * @interface TypedDeclaration * @extends {Declaration} */ export interface TypedDeclaration extends Declaration { /** * The type of the declaration. * * @type {(string | undefined)} * @example "string" * @example "Declaration[]" * @memberof TypedDeclaration */ type: string | undefined; } /** * Interface for generic type declarations. Those declarations are able to be used in a generic way. * Examples are: classes, interfaces, methods and such. * * @export * @interface GenericDeclaration * @extends {Declaration} */ export interface GenericDeclaration extends Declaration { /** * List of type parameters * * @type {(string[] | undefined)} * @memberof GenericDeclaration * * @example * ['T', 'TResult', 'TError'] */ typeParameters: string[] | undefined; } /** * Interface for exportable declarations. Does contain information about the export status of a declaration. * * @export * @interface ExportableDeclaration * @extends {Declaration} */ export interface ExportableDeclaration extends Declaration { /** * Indicates if the declaration is exported (i.e. export function ...) or not. * * @type {boolean} * @memberof ExportableDeclaration */ isExported: boolean; } /** * Interface for visible declarations. Does contain information about the visibility of the declaration. * * @export * @interface ScopedDeclaration * @extends {Declaration} */ export interface ScopedDeclaration extends Declaration { /** * Defines the visibility scope of the declaration. Can be undefined, in which case there * is no visibility given (e.g. methods in interfaces). * * @type {(DeclarationVisibility | undefined)} * @memberof ScopedDeclaration */ visibility: DeclarationVisibility | undefined; } /** * Interface for class like constructs. Contain properties and methods that are contained. * Examples are classes, interfaces, abstract classes, etc. * * @export * @interface ClassLikeDeclaration * @extends {Declaration} */ export interface ClassLikeDeclaration extends Declaration { /** * Accessors of this class. * * @type {AccessorDeclaration[]} * @memberof ClassLikeDeclaration */ accessors: AccessorDeclaration[]; /** * The properties of the declaration. * * @type {PropertyDeclaration[]} * @memberof ClassLikeDeclaration */ properties: PropertyDeclaration[]; /** * The methods of the declaration. * * @type {MethodDeclaration[]} * @memberof ClassLikeDeclaration */ methods: MethodDeclaration[]; } /** * Interface for callable declarations. Contains lists for parameters and used variables in the callable * definitions. * * @export * @interface CallableDeclaration * @extends {Declaration} */ export interface CallableDeclaration extends Declaration { /** * List of used parameters in the callable node. * * @type {ParameterDeclaration[]} * @memberof CallableDeclaration */ parameters: ParameterDeclaration[]; /** * List of used variables in the callable node. * * @type {VariableDeclaration[]} * @memberof CallableDeclaration */ variables: VariableDeclaration[]; } /** * Interface for possible abstract declarations. Contains information if the element is abstract or not. * * @export * @interface AbstractDeclaration * @extends {Declaration} */ export interface AbstractDeclaration extends Declaration { /** * Defines if the declaration is abstract or not. * * @type {boolean} * @memberof AbstractDeclaration */ isAbstract: boolean; } /** * Interface for possible optional declarations. Contains information if the element is optional or not. * * @export * @interface OptionalDeclaration * @extends {Declaration} */ export interface OptionalDeclaration extends Declaration { /** * Defines if the declaration is optional or not. * * @type {boolean} * @memberof OptionalDeclaration */ isOptional: boolean; } /** * Interface for possible static declarations. * * @export * @interface StaticDeclaration * @extends {Declaration} */ export interface StaticDeclaration extends Declaration { /** * Defines if the declaration is static or not. * * @type {boolean} * @memberof StaticDeclaration */ isStatic: boolean; } /** * Interface for possible async declarations. * * @export * @interface AsyncDeclaration * @extends {Declaration} */ export interface AsyncDeclaration extends Declaration { /** * Defines if the declaration is async or not. * * @type {boolean} * @memberof AsyncDeclaration */ isAsync: boolean; } ================================================ FILE: src/declarations/DeclarationInfo.ts ================================================ import { Declaration } from './Declaration'; /** * Class that defines information about a declaration. * Contains the declaration and the origin of the declaration. * * @export * @class DeclarationInfo */ export class DeclarationInfo { constructor(public declaration: Declaration, public from: string) { } } ================================================ FILE: src/declarations/DeclarationVisibility.ts ================================================ /** * Returns the visibility string for a given enum value. * * @param {DeclarationVisibility} [visibility] * @returns {string} */ export function getVisibilityText(visibility?: DeclarationVisibility): string { switch (visibility) { case DeclarationVisibility.Private: return 'private'; case DeclarationVisibility.Public: return 'public'; case DeclarationVisibility.Protected: return 'protected'; default: return ''; } } /** * Visibility of a class or interface property, as well as a method. * * @export * @enum {number} */ export const enum DeclarationVisibility { Private, Protected, Public, } ================================================ FILE: src/declarations/DefaultDeclaration.ts ================================================ import { Resource } from '../resources/Resource'; import { Declaration, ExportableDeclaration } from './Declaration'; /** * Default declaration. Is used when a file exports something as its default. * Primary use is to ask the user about a name for the default export. * Is kind of an abstract declaration since there is no real declaration. * * @export * @class DefaultDeclaration * @implements {ExportableDeclaration} */ export class DefaultDeclaration implements ExportableDeclaration { public readonly isExported: boolean = true; private exported: Declaration | undefined; public get exportedDeclaration(): Declaration { if (!this.exported) { this.exported = this.resource.declarations.find(o => o.name === this.name)!; } return this.exported; } constructor( public name: string, private resource: Resource, public start?: number, public end?: number, ) { } } ================================================ FILE: src/declarations/EnumDeclaration.ts ================================================ import { ExportableDeclaration } from './Declaration'; /** * Enum declaration. * * @export * @class EnumDeclaration * @implements {ExportableDeclaration} */ export class EnumDeclaration implements ExportableDeclaration { public members: string[] = []; constructor( public name: string, public isExported: boolean, public start?: number, public end?: number, ) { } } ================================================ FILE: src/declarations/FunctionDeclaration.ts ================================================ import { AsyncDeclaration, CallableDeclaration, ExportableDeclaration } from './Declaration'; import { ParameterDeclaration } from './ParameterDeclaration'; import { VariableDeclaration } from './VariableDeclaration'; /** * Function declaration. Like the MethodDeclaration it contains the base info about the function * and additional stuff. * * @export * @class FunctionDeclaration * @implements {CallableDeclaration} * @implements {ExportableDeclaration} */ export class FunctionDeclaration implements AsyncDeclaration, CallableDeclaration, ExportableDeclaration { public parameters: ParameterDeclaration[] = []; public variables: VariableDeclaration[] = []; constructor( public name: string, public isExported: boolean, public isAsync: boolean, public type?: string, public start?: number, public end?: number, ) { } } ================================================ FILE: src/declarations/InterfaceDeclaration.ts ================================================ import { AccessorDeclaration } from './AccessorDeclaration'; import { ClassLikeDeclaration, ExportableDeclaration, GenericDeclaration } from './Declaration'; import { MethodDeclaration } from './MethodDeclaration'; import { PropertyDeclaration } from './PropertyDeclaration'; /** * Interface declaration that contains defined properties and methods. * * @export * @class InterfaceDeclaration * @implements {ExportableDeclaration} * @implements {GenericDeclaration} */ export class InterfaceDeclaration implements ClassLikeDeclaration, ExportableDeclaration, GenericDeclaration { public accessors: AccessorDeclaration[] = []; public typeParameters: string[] | undefined; public properties: PropertyDeclaration[] = []; public methods: MethodDeclaration[] = []; constructor( public name: string, public isExported: boolean, public start?: number, public end?: number, ) { } } ================================================ FILE: src/declarations/MethodDeclaration.ts ================================================ import { AbstractDeclaration, AsyncDeclaration, CallableDeclaration, OptionalDeclaration, ScopedDeclaration, StaticDeclaration, TypedDeclaration, } from './Declaration'; import { DeclarationVisibility } from './DeclarationVisibility'; import { ParameterDeclaration } from './ParameterDeclaration'; import { VariableDeclaration } from './VariableDeclaration'; /** * Method declaration. A method is contained in an interface or a class. * Contains information abount the method itself. * * @export * @class MethodDeclaration * @implements {CallableDeclaration} * @implements {ScopedDeclaration} * @implements {TypedDeclaration} */ export class MethodDeclaration implements AbstractDeclaration, AsyncDeclaration, CallableDeclaration, OptionalDeclaration, ScopedDeclaration, StaticDeclaration, TypedDeclaration { public parameters: ParameterDeclaration[] = []; public variables: VariableDeclaration[] = []; constructor( public name: string, public isAbstract: boolean, public visibility: DeclarationVisibility | undefined, public type: string | undefined, public isOptional: boolean, public isStatic: boolean, public isAsync: boolean, public start?: number, public end?: number, ) { } } ================================================ FILE: src/declarations/ModuleDeclaration.ts ================================================ import { Declaration } from './Declaration'; /** * Module (namespace) declaration. Does export a whole module or namespace that is mainly used by * external declaration files. * * @export * @class ModuleDeclaration * @implements {Declaration} */ export class ModuleDeclaration implements Declaration { constructor( public name: string, public start?: number, public end?: number, ) { } } ================================================ FILE: src/declarations/ParameterDeclaration.ts ================================================ import { TypedDeclaration } from './Declaration'; /** * Parameter declaration. Is contained in a method or function delaration since a parameter can not be exported * by itself. * * @export * @class ParameterDeclaration * @implements {TypedDeclaration} */ export class ParameterDeclaration implements TypedDeclaration { constructor(public name: string, public type: string | undefined, public start?: number, public end?: number) { } } export class BoundParameterDeclaration extends ParameterDeclaration { public parameters: ParameterDeclaration[] = []; public typeReference: string | undefined; public get name(): string { return this.parameters.length ? `${this.startCharacter} ${this.parameters.map(p => p.name).join(', ')} ${this.endCharacter}` : this.startCharacter + this.endCharacter; } public set name(_: string) { } public get type(): string { return this.typeReference || this.parameters.length ? `{ ${this.parameters.map(p => p.type).join(', ')} }` : this.startCharacter + this.endCharacter; } public set type(_: string) { } constructor(private startCharacter: string, private endCharacter: string, start?: number, end?: number) { super('', '', start, end); } } export class ObjectBoundParameterDeclaration extends BoundParameterDeclaration { constructor(start?: number, end?: number) { super('{', '}', start, end); } } export class ArrayBoundParameterDeclaration extends BoundParameterDeclaration { constructor(start?: number, end?: number) { super('[', ']', start, end); } } ================================================ FILE: src/declarations/PropertyDeclaration.ts ================================================ import { OptionalDeclaration, ScopedDeclaration, StaticDeclaration, TypedDeclaration } from './Declaration'; import { DeclarationVisibility } from './DeclarationVisibility'; /** * Property declaration that contains its visibility. * * @export * @class PropertyDeclaration * @implements {ScopedDeclaration} * @implements {TypedDeclaration} */ export class PropertyDeclaration implements OptionalDeclaration, ScopedDeclaration, StaticDeclaration, TypedDeclaration { constructor( public name: string, public visibility: DeclarationVisibility | undefined, public type: string | undefined, public isOptional: boolean, public isStatic: boolean, public start?: number, public end?: number, ) { } } ================================================ FILE: src/declarations/TypeAliasDeclaration.ts ================================================ import { ExportableDeclaration } from './Declaration'; /** * Alias declaration that can be exported. Is used to defined types. * (e.g. type Foobar = { name: string };) * * @export * @class TypeAliasDeclaration * @implements {ExportableDeclaration} */ export class TypeAliasDeclaration implements ExportableDeclaration { constructor( public name: string, public isExported: boolean, public start?: number, public end?: number, ) { } } ================================================ FILE: src/declarations/VariableDeclaration.ts ================================================ import { ExportableDeclaration, TypedDeclaration } from './Declaration'; /** * Variable declaration. Is contained in a method or function, or can be exported. * * @export * @class VariableDeclaration * @implements {ExportableDeclaration} * @implements {TypedDeclaration} */ export class VariableDeclaration implements ExportableDeclaration, TypedDeclaration { constructor( public name: string, public isConst: boolean, public isExported: boolean, public type: string | undefined, public start?: number, public end?: number, ) { } } ================================================ FILE: src/declarations/index.ts ================================================ export * from './AccessorDeclaration'; export * from './ClassDeclaration'; export * from './ConstructorDeclaration'; export * from './Declaration'; export * from './DeclarationInfo'; export * from './DeclarationVisibility'; export * from './DefaultDeclaration'; export * from './EnumDeclaration'; export * from './FunctionDeclaration'; export * from './InterfaceDeclaration'; export * from './MethodDeclaration'; export * from './ModuleDeclaration'; export * from './ParameterDeclaration'; export * from './PropertyDeclaration'; export * from './TypeAliasDeclaration'; export * from './VariableDeclaration'; ================================================ FILE: src/errors/NotGeneratableYetError.ts ================================================ import { Generatable } from '../code-generators/TypescriptCodeGenerator'; /** * Error that should be thrown, when a generatable is not yet able to be generated. * * @export * @class NotGeneratableYetError * @extends {Error} */ export class NotGeneratableYetError extends Error { constructor(generatable: Generatable) { super(); this.message = `The element "${generatable.constructor.name}" is not yet generatable.`; } } ================================================ FILE: src/exports/AllExport.ts ================================================ import { Export } from './Export'; /** * Declares an all export (i.e. export * from ...). * * @export * @class AllExport * @implements {Export} */ export class AllExport implements Export { constructor(public start: number, public end: number, public from: string) { } } ================================================ FILE: src/exports/AssignedExport.ts ================================================ import { ExportableDeclaration } from '../declarations/Declaration'; import { Module } from '../resources/Module'; import { Namespace } from '../resources/Namespace'; import { Resource } from '../resources/Resource'; import { isExportableDeclaration } from '../type-guards/TypescriptHeroGuards'; import { Export } from './Export'; /** * Declares an all export (i.e. export * from ...). * * @export * @class AssignedExport * @implements {Export} */ export class AssignedExport implements Export { /** * Returns a list of exported objects of this export. * This returns a list of possible exportable declarations or further exported resources. * * @readonly * @type {((ExportableDeclaration | Resource)[])} * @memberof AssignedExport */ public get exported(): (ExportableDeclaration | Resource)[] { return <(ExportableDeclaration | Resource)[]>[ ...this.resource.declarations .filter(o => isExportableDeclaration(o) && o.isExported && o.name === this.declarationIdentifier), ...this.resource.resources .filter(o => (o instanceof Namespace || o instanceof Module) && o.name === this.declarationIdentifier), ]; } constructor( public start: number, public end: number, public declarationIdentifier: string, private resource: Resource, ) { } } ================================================ FILE: src/exports/Export.ts ================================================ import { Node } from '../Node'; /** * Basic export interface. Defines an export in a document. * * @export * @interface Export * @extends {Node} */ export interface Export extends Node { } ================================================ FILE: src/exports/NamedExport.ts ================================================ import { SymbolSpecifier } from '../SymbolSpecifier'; import { Export } from './Export'; /** * Declares a named export (i.e. export { Foobar } from ...). * * @export * @class NamedExport * @implements {Export} */ export class NamedExport implements Export { public specifiers: SymbolSpecifier[] | undefined; constructor(public start: number, public end: number, public from: string) { } } ================================================ FILE: src/exports/index.ts ================================================ export * from './AllExport'; export * from './AssignedExport'; export * from './Export'; export * from './NamedExport'; ================================================ FILE: src/imports/ExternalModuleImport.ts ================================================ import { AliasedImport } from './Import'; /** * Alternative to the namespace import. Can be used by various libraries. * (i.e. import foobar = require('foobar')). * * @export * @class ExternalModuleImport * @implements {AliasedImport} */ export class ExternalModuleImport implements AliasedImport { public get isNew(): boolean { return this.start === undefined || this.end === undefined; } constructor(public libraryName: string, public alias: string, public start?: number, public end?: number) { } /** * Clone the current import object. * * @returns {ExternalModuleImport} * * @memberof ExternalModuleImport */ public clone(): ExternalModuleImport { return new ExternalModuleImport(this.libraryName, this.alias, this.start, this.end); } } ================================================ FILE: src/imports/Import.ts ================================================ import { Clonable } from '../clonable/Clonable'; import { Node } from '../Node'; /** * Basic import interface. Defines an import in a document. * If no start and end points are given, the import is considered "new". * * @export * @interface Import */ export interface Import extends Clonable, Node { /** * Indicates if the given import is "new" or a parsed one. * * @type {boolean} * @memberof Import */ readonly isNew: boolean; /** * The library name of the given import (This actually is the part after the import statement). * * @example "express" * * @type {string} * @memberof Import */ libraryName: string; } /** * Basic interface for aliased imports. Defines an alias for namespace imports and other aliased imports. * * @export * @interface AliasedImport * @extends {Import} */ export interface AliasedImport extends Import { /** * Alias for the given import. E.g. for a "* as ..." import. * * @type {string} * @memberof AliasedImport */ alias: string; } ================================================ FILE: src/imports/NamedImport.ts ================================================ import { SymbolSpecifier } from '../SymbolSpecifier'; import { Import } from './Import'; /** * Basic typescript import (ES6 style). Does contain multiple symbols of a file and converts * itself to a multiline import if the threshold is reached. * Can also contain a default import part. * (i.e. import {Foobar} from ...). * * @export * @class NamedImport * @implements {Import} */ export class NamedImport implements Import { public specifiers: SymbolSpecifier[] = []; public defaultAlias?: string; public get isNew(): boolean { return this.start === undefined || this.end === undefined; } constructor(public libraryName: string, public start?: number, public end?: number) { } /** * Clone the current import object. * * @returns {NamedImport} * * @memberof NamedImport */ public clone(): NamedImport { const clone = new NamedImport(this.libraryName, this.start, this.end); clone.specifiers = this.specifiers.map(o => o.clone()); clone.defaultAlias = this.defaultAlias; return clone; } } ================================================ FILE: src/imports/NamespaceImport.ts ================================================ import { AliasedImport } from './Import'; /** * Import that imports a whole namespace (i.e. import * as foobar from 'foobar';). * * @export * @class TsNamespaceImport * @implements {AliasedImport} */ export class NamespaceImport implements AliasedImport { public get isNew(): boolean { return this.start === undefined || this.end === undefined; } constructor(public libraryName: string, public alias: string, public start?: number, public end?: number) { } /** * Clone the current import object. * * @returns {NamespaceImport} * * @memberof NamespaceImport */ public clone(): NamespaceImport { return new NamespaceImport(this.libraryName, this.alias, this.start, this.end); } } ================================================ FILE: src/imports/StringImport.ts ================================================ import { Import } from './Import'; /** * Simple string import (i.e. import "reflect-metadata";). * * @export * @class StringImport * @implements {Import} */ export class StringImport implements Import { public get isNew(): boolean { return this.start === undefined || this.end === undefined; } constructor(public libraryName: string, public start?: number, public end?: number) { } /** * Clone the current import object. * * @returns {StringImport} * * @memberof StringImport */ public clone(): StringImport { return new StringImport(this.libraryName, this.start, this.end); } } ================================================ FILE: src/imports/index.ts ================================================ export * from './ExternalModuleImport'; export * from './Import'; export * from './NamedImport'; export * from './NamespaceImport'; export * from './StringImport'; ================================================ FILE: src/index.ts ================================================ export * from './TypescriptParser'; export * from './Node'; export * from './SymbolSpecifier'; export * from './DeclarationIndex'; export * from './code-generators/TypescriptGenerationOptions'; export * from './code-generators/TypescriptCodeGenerator'; export * from './declarations'; export * from './exports'; export * from './imports'; export * from './resources'; export * from './type-guards/TypescriptHeroGuards'; ================================================ FILE: src/node-parser/class-parser.ts ================================================ import { ArrayBindingPattern, ClassDeclaration, ConstructorDeclaration, Identifier, Node, ObjectBindingPattern, SyntaxKind, } from 'typescript'; import { GetterDeclaration, SetterDeclaration } from '../declarations/AccessorDeclaration'; import { ClassDeclaration as TshClass } from '../declarations/ClassDeclaration'; import { ConstructorDeclaration as TshConstructor } from '../declarations/ConstructorDeclaration'; import { DefaultDeclaration as TshDefault } from '../declarations/DefaultDeclaration'; import { MethodDeclaration as TshMethod } from '../declarations/MethodDeclaration'; import { ParameterDeclaration as TshParameter } from '../declarations/ParameterDeclaration'; import { PropertyDeclaration as TshProperty } from '../declarations/PropertyDeclaration'; import { Resource } from '../resources/Resource'; import { isArrayBindingPattern, isConstructorDeclaration, isGetAccessorDeclaration, isIdentifier, isMethodDeclaration, isObjectBindingPattern, isPropertyDeclaration, isSetAccessorDeclaration, } from '../type-guards/TypescriptGuards'; import { parseFunctionParts, parseMethodParams } from './function-parser'; import { parseIdentifier } from './identifier-parser'; import { containsModifier, getDefaultResourceIdentifier, getNodeType, getNodeVisibility, isNodeDefaultExported, isNodeExported, } from './parse-utilities'; /** * Parses the identifiers of a class (usages). * * @export * @param {Resource} tsResource * @param {Node} node */ export function parseClassIdentifiers(tsResource: Resource, node: Node): void { for (const child of node.getChildren()) { switch (child.kind) { case SyntaxKind.Identifier: parseIdentifier(tsResource, child); break; default: break; } parseClassIdentifiers(tsResource, child); } } /** * Parse information about a constructor. Contains parameters and used modifiers * (i.e. constructor(private name: string)). * * @export * @param {TshClass} parent * @param {TshConstructor} ctor * @param {ConstructorDeclaration} node */ export function parseCtorParams( parent: TshClass, ctor: TshConstructor, node: ConstructorDeclaration, ): void { if (!node.parameters) { return; } node.parameters.forEach((o) => { if (isIdentifier(o.name)) { ctor.parameters.push( new TshParameter( (o.name as Identifier).text, getNodeType(o.type), o.getStart(), o.getEnd(), ), ); if (!o.modifiers) { return; } parent.properties.push( new TshProperty( (o.name as Identifier).text, getNodeVisibility(o), getNodeType(o.type), !!o.questionToken, containsModifier(o, SyntaxKind.StaticKeyword), o.getStart(), o.getEnd(), ), ); } else if (isObjectBindingPattern(o.name) || isArrayBindingPattern(o.name)) { const identifiers = o.name as ObjectBindingPattern | ArrayBindingPattern; const elements = [...identifiers.elements]; // TODO: BindingElement ctor.parameters = ctor.parameters.concat(elements.map((bind: any) => { if (isIdentifier(bind.name)) { return new TshParameter( (bind.name as Identifier).text, undefined, bind.getStart(), bind.getEnd(), ); } }).filter(Boolean)); } }); } /** * Parses a class node into its declaration. Calculates the properties, constructors and methods of the class. * * @export * @param {Resource} tsResource * @param {ClassDeclaration} node */ export function parseClass(tsResource: Resource, node: ClassDeclaration): void { const name = node.name ? node.name.text : getDefaultResourceIdentifier(tsResource); const classDeclaration = new TshClass(name, isNodeExported(node), node.getStart(), node.getEnd()); if (isNodeDefaultExported(node)) { classDeclaration.isExported = false; tsResource.declarations.push(new TshDefault(classDeclaration.name, tsResource)); } if (node.typeParameters) { classDeclaration.typeParameters = node.typeParameters.map(param => param.getText()); } if (node.members) { node.members.forEach((o) => { if (isPropertyDeclaration(o)) { const actualCount = classDeclaration.properties.length; if (o.modifiers) { classDeclaration.properties.push( new TshProperty( (o.name as Identifier).text, getNodeVisibility(o), getNodeType(o.type), !!o.questionToken, containsModifier(o, SyntaxKind.StaticKeyword), o.getStart(), o.getEnd(), ), ); } if (actualCount === classDeclaration.properties.length) { classDeclaration.properties.push( new TshProperty( (o.name as Identifier).text, getNodeVisibility(o), getNodeType(o.type), !!o.questionToken, containsModifier(o, SyntaxKind.StaticKeyword), o.getStart(), o.getEnd(), ), ); } return; } if (isGetAccessorDeclaration(o)) { classDeclaration.accessors.push( new GetterDeclaration( (o.name as Identifier).text, getNodeVisibility(o), getNodeType(o.type), o.modifiers !== undefined && o.modifiers.some(m => m.kind === SyntaxKind.AbstractKeyword), containsModifier(o, SyntaxKind.StaticKeyword), o.getStart(), o.getEnd(), ), ); } if (isSetAccessorDeclaration(o)) { classDeclaration.accessors.push( new SetterDeclaration( (o.name as Identifier).text, getNodeVisibility(o), getNodeType(o.type), o.modifiers !== undefined && o.modifiers.some(m => m.kind === SyntaxKind.AbstractKeyword), containsModifier(o, SyntaxKind.StaticKeyword), o.getStart(), o.getEnd(), ), ); } if (isConstructorDeclaration(o)) { const ctor = new TshConstructor(classDeclaration.name, o.getStart(), o.getEnd()); parseCtorParams(classDeclaration, ctor, o); classDeclaration.ctor = ctor; parseFunctionParts(tsResource, ctor, o); } else if (isMethodDeclaration(o)) { const method = new TshMethod( (o.name as Identifier).text, o.modifiers !== undefined && o.modifiers.some(m => m.kind === SyntaxKind.AbstractKeyword), getNodeVisibility(o), getNodeType(o.type), !!o.questionToken, containsModifier(o, SyntaxKind.StaticKeyword), containsModifier(o, SyntaxKind.AsyncKeyword), o.getStart(), o.getEnd(), ); method.parameters = parseMethodParams(o); classDeclaration.methods.push(method); parseFunctionParts(tsResource, method, o); } }); } parseClassIdentifiers(tsResource, node); tsResource.declarations.push(classDeclaration); } ================================================ FILE: src/node-parser/enum-parser.ts ================================================ import { EnumDeclaration } from 'typescript'; import { EnumDeclaration as TshEnum } from '../declarations/EnumDeclaration'; import { Resource } from '../resources/Resource'; import { isNodeExported } from './parse-utilities'; /** * Parses an enum node into the declaration. * * @export * @param {resource} resource * @param {EnumDeclaration} node */ export function parseEnum(resource: Resource, node: EnumDeclaration): void { const declaration = new TshEnum( node.name.text, isNodeExported(node), node.getStart(), node.getEnd(), ); declaration.members = node.members.map(o => o.name.getText()); resource.declarations.push(declaration); } ================================================ FILE: src/node-parser/export-parser.ts ================================================ import { ExportAssignment, ExportDeclaration, Identifier, StringLiteral } from 'typescript'; import { DefaultDeclaration } from '../declarations/DefaultDeclaration'; import { AllExport } from '../exports/AllExport'; import { AssignedExport } from '../exports/AssignedExport'; import { NamedExport } from '../exports/NamedExport'; import { Resource } from '../resources/Resource'; import { SymbolSpecifier } from '../SymbolSpecifier'; import { isExportDeclaration, isNamedExports, isStringLiteral } from '../type-guards/TypescriptGuards'; import { getDefaultResourceIdentifier } from './parse-utilities'; /** * Parses an export node into the declaration. * * @export * @param {Resource} resource * @param {(ExportDeclaration | ExportAssignment)} node */ export function parseExport(resource: Resource, node: ExportDeclaration | ExportAssignment): void { if (isExportDeclaration(node)) { const tsExport = node as ExportDeclaration; if (!isStringLiteral(tsExport.moduleSpecifier) && !tsExport.exportClause) { return; } if (tsExport.getText().indexOf('*') > -1) { resource.exports.push( new AllExport( node.getStart(), node.getEnd(), (tsExport.moduleSpecifier as StringLiteral).text, ), ); } else if (tsExport.exportClause && isNamedExports(tsExport.exportClause)) { const lib = tsExport.moduleSpecifier as StringLiteral; const ex = new NamedExport( node.getStart(), node.getEnd(), lib ? lib.text : getDefaultResourceIdentifier(resource), ); ex.specifiers = tsExport.exportClause.elements.map( o => o.propertyName && o.name ? new SymbolSpecifier(o.propertyName.text, o.name.text) : new SymbolSpecifier(o.name.text), ); for (const spec of ex.specifiers) { if (resource.usages.indexOf(spec.alias || spec.specifier) === -1) { resource.usages.push(spec.alias || spec.specifier); } } resource.exports.push(ex); } } else { const literal = node.expression as Identifier; if (node.isExportEquals) { resource.exports.push(new AssignedExport(node.getStart(), node.getEnd(), literal.text, resource)); if (resource.usages.indexOf(literal.text) === -1) { resource.usages.push(literal.text); } } else { const name = (literal && literal.text) ? literal.text : getDefaultResourceIdentifier(resource); if (resource.usages.indexOf(name) === -1) { resource.usages.push(name); } resource.declarations.push(new DefaultDeclaration(name, resource)); } } } ================================================ FILE: src/node-parser/function-parser.ts ================================================ import { FunctionDeclaration, Identifier, isTupleTypeNode, isTypeLiteralNode, isTypeReferenceNode, MethodDeclaration, MethodSignature, Node, ParameterDeclaration, PropertySignature, SyntaxKind, VariableStatement, } from 'typescript'; import { ConstructorDeclaration as TshConstructor } from '../declarations/ConstructorDeclaration'; import { DefaultDeclaration as TshDefault } from '../declarations/DefaultDeclaration'; import { FunctionDeclaration as TshFunction } from '../declarations/FunctionDeclaration'; import { MethodDeclaration as TshMethod } from '../declarations/MethodDeclaration'; import { ArrayBoundParameterDeclaration, ObjectBoundParameterDeclaration, ParameterDeclaration as TshParameter, } from '../declarations/ParameterDeclaration'; import { Resource } from '../resources/Resource'; import { isArrayBindingPattern, isIdentifier, isObjectBindingPattern, isPropertySignature, } from '../type-guards/TypescriptGuards'; import { parseIdentifier } from './identifier-parser'; import { containsModifier, getDefaultResourceIdentifier, getNodeType, isNodeDefaultExported, isNodeExported, } from './parse-utilities'; import { parseVariable } from './variable-parser'; /** * Parse the parts of a function. All functions / methods contain various information about used variables * and parameters. * * @export * @param {Resource} resource * @param {(TshConstructor | TshMethod | TshFunction)} parent * @param {Node} node */ export function parseFunctionParts( resource: Resource, parent: TshConstructor | TshMethod | TshFunction, node: Node, ): void { for (const child of node.getChildren()) { switch (child.kind) { case SyntaxKind.Identifier: parseIdentifier(resource, child); break; case SyntaxKind.VariableStatement: parseVariable(parent, child); break; default: break; } parseFunctionParts(resource, parent, child); } } /** * Parse method parameters. * * @export * @param {(FunctionDeclaration | MethodDeclaration | MethodSignature)} node * @returns {TshParameter[]} */ export function parseMethodParams( node: FunctionDeclaration | MethodDeclaration | MethodSignature, ): TshParameter[] { return node.parameters.reduce( (all: TshParameter[], cur: ParameterDeclaration) => { const params = all; if (isIdentifier(cur.name)) { params.push(new TshParameter( (cur.name as Identifier).text, getNodeType(cur.type), cur.getStart(), cur.getEnd(), )); } else if (isObjectBindingPattern(cur.name)) { const elements = cur.name.elements; let types: (string | undefined)[] = []; const boundParam = new ObjectBoundParameterDeclaration(cur.getStart(), cur.getEnd()); if (cur.type && isTypeReferenceNode(cur.type)) { boundParam.typeReference = getNodeType(cur.type); } else if (cur.type && isTypeLiteralNode(cur.type)) { types = cur.type.members .filter(member => isPropertySignature(member)) .map((signature: any) => getNodeType((signature as PropertySignature).type)); } boundParam.parameters = elements.map((bindingElement, index) => new TshParameter( bindingElement.name.getText(), types[index], bindingElement.getStart(), bindingElement.getEnd(), )); params.push(boundParam); } else if (isArrayBindingPattern(cur.name)) { const elements = cur.name.elements; let types: (string | undefined)[] = []; const boundParam = new ArrayBoundParameterDeclaration(cur.getStart(), cur.getEnd()); if (cur.type && isTypeReferenceNode(cur.type)) { boundParam.typeReference = getNodeType(cur.type); } else if (cur.type && isTupleTypeNode(cur.type)) { types = cur.type.elementTypes.map(type => getNodeType(type)); } boundParam.parameters = elements.map((bindingElement, index) => new TshParameter( bindingElement.getText(), types[index], bindingElement.getStart(), bindingElement.getEnd(), )); params.push(boundParam); } return params; }, [], ); } /** * Parses a function into its declaration. * Parses the functions sub information like parameters and variables. * * @export * @param {Resource} resource * @param {FunctionDeclaration} node */ export function parseFunction(resource: Resource, node: FunctionDeclaration): void { const name = node.name ? node.name.text : getDefaultResourceIdentifier(resource); const func = new TshFunction( name, isNodeExported(node), containsModifier(node, SyntaxKind.AsyncKeyword), getNodeType(node.type), node.getStart(), node.getEnd(), ); if (isNodeDefaultExported(node)) { func.isExported = false; resource.declarations.push(new TshDefault(func.name, resource)); } func.parameters = parseMethodParams(node); resource.declarations.push(func); parseFunctionParts(resource, func, node); } ================================================ FILE: src/node-parser/identifier-parser.ts ================================================ import { Identifier, Node, SyntaxKind } from 'typescript'; import { Resource } from '../resources/Resource'; const usageNotAllowedParents = [ SyntaxKind.ImportEqualsDeclaration, SyntaxKind.ImportSpecifier, SyntaxKind.NamespaceImport, SyntaxKind.ClassDeclaration, SyntaxKind.ImportEqualsDeclaration, SyntaxKind.ImportClause, SyntaxKind.ImportDeclaration, SyntaxKind.InterfaceDeclaration, SyntaxKind.ExportDeclaration, SyntaxKind.ExportSpecifier, SyntaxKind.ImportSpecifier, SyntaxKind.FunctionDeclaration, SyntaxKind.EnumDeclaration, SyntaxKind.TypeAliasDeclaration, SyntaxKind.MethodDeclaration, ]; const usageAllowedIfLast = [ SyntaxKind.Parameter, SyntaxKind.PropertyDeclaration, SyntaxKind.VariableDeclaration, SyntaxKind.BinaryExpression, ]; const usagePredicates: ((node: Node) => boolean)[] = [ (o: Node) => o.parent !== undefined && usageNotAllowedParents.indexOf(o.parent.kind) === -1, allowedIfLastIdentifier, allowedIfPropertyAccessFirst, ]; /** * Predicate function to determine if the node is possible as a "usage". * Checks for the node identifier to be the last of the identifier list. * * @param {Node} node * @returns {boolean} */ function allowedIfLastIdentifier(node: Node): boolean { if (!node.parent) { return false; } if (usageAllowedIfLast.indexOf(node.parent.kind) === -1) { return true; } const children = node.parent.getChildren().filter(o => o.kind === SyntaxKind.Identifier); return children.length === 1 || children.indexOf(node) === 1; } /** * Predicate function to determine if the node is possible as a "usage". * Checks if the identifier is on the lefthand side of a property access. * * @param {Node} node * @returns {boolean} */ function allowedIfPropertyAccessFirst(node: Node): boolean { if (!node.parent) { return false; } if (node.parent.kind !== SyntaxKind.PropertyAccessExpression) { return true; } const children = node.parent.getChildren(); return children.indexOf(node) === 0; } /** * Parses an identifier into a usage of a resource if the predicates are true. * * @export * @param {Resource} resource * @param {Identifier} node */ export function parseIdentifier(resource: Resource, node: Identifier): void { if (node.parent && usagePredicates.every(predicate => predicate(node))) { if (resource.usages.indexOf(node.text) === -1) { resource.usages.push(node.text); } } } ================================================ FILE: src/node-parser/import-parser.ts ================================================ import { ExternalModuleReference, Identifier, ImportDeclaration, ImportEqualsDeclaration, NamedImports, NamespaceImport as TsNamespaceImport, StringLiteral, } from 'typescript'; import { ExternalModuleImport } from '../imports/ExternalModuleImport'; import { NamedImport } from '../imports/NamedImport'; import { NamespaceImport } from '../imports/NamespaceImport'; import { StringImport } from '../imports/StringImport'; import { Resource } from '../resources/Resource'; import { SymbolSpecifier } from '../SymbolSpecifier'; import { isExternalModuleReference, isImportDeclaration, isNamedImports, isNamespaceImport, isStringLiteral, } from '../type-guards/TypescriptGuards'; /** * Parses an import node into the declaration. * * @export * @param {Resource} resource * @param {(ImportDeclaration | ImportEqualsDeclaration)} node */ export function parseImport(resource: Resource, node: ImportDeclaration | ImportEqualsDeclaration): void { if (isImportDeclaration(node)) { if (node.importClause && isNamespaceImport(node.importClause.namedBindings)) { const lib = node.moduleSpecifier as StringLiteral; const alias = (node.importClause.namedBindings as TsNamespaceImport).name as Identifier; resource.imports.push(new NamespaceImport(lib.text, alias.text, node.getStart(), node.getEnd())); } else if (node.importClause && (isNamedImports(node.importClause.namedBindings) || node.importClause.name)) { const lib = node.moduleSpecifier as StringLiteral; const tsImport = new NamedImport(lib.text, node.getStart(), node.getEnd()); if (node.importClause.name) { tsImport.defaultAlias = node.importClause.name.text; } if (node.importClause.namedBindings) { const bindings = node.importClause.namedBindings as NamedImports; tsImport.specifiers = bindings.elements.map( o => o.propertyName && o.name ? new SymbolSpecifier(o.propertyName.text, o.name.text) : new SymbolSpecifier(o.name.text), ); const defaultImport = tsImport.specifiers.find(imp => imp.specifier === 'default' && !!imp.alias); if (defaultImport) { tsImport.specifiers.splice(tsImport.specifiers.indexOf(defaultImport), 1); tsImport.defaultAlias = defaultImport.alias; } } resource.imports.push(tsImport); } else if (node.moduleSpecifier && isStringLiteral(node.moduleSpecifier)) { const lib = node.moduleSpecifier as StringLiteral; resource.imports.push(new StringImport(lib.text, node.getStart(), node.getEnd())); } } else if (isExternalModuleReference(node.moduleReference)) { const alias = node.name; const lib = (node.moduleReference as ExternalModuleReference).expression as Identifier; resource.imports.push(new ExternalModuleImport(lib.text, alias.text, node.getStart(), node.getEnd())); } } ================================================ FILE: src/node-parser/index.ts ================================================ // export * from './class-parser'; // export * from './enum-parser'; // export * from './export-parser'; // export * from './function-parser'; // export * from './identifier-parser'; // export * from './import-parser'; // export * from './interface-parser'; // export * from './module-parser'; // export * from './type-alias-parser'; // export * from './variable-parser'; ================================================ FILE: src/node-parser/interface-parser.ts ================================================ import { Identifier, InterfaceDeclaration, SyntaxKind } from 'typescript'; import { DeclarationVisibility } from '../declarations/DeclarationVisibility'; import { DefaultDeclaration } from '../declarations/DefaultDeclaration'; import { InterfaceDeclaration as TshInterface } from '../declarations/InterfaceDeclaration'; import { MethodDeclaration } from '../declarations/MethodDeclaration'; import { PropertyDeclaration } from '../declarations/PropertyDeclaration'; import { Resource } from '../resources/Resource'; import { isMethodSignature, isPropertySignature } from '../type-guards/TypescriptGuards'; import { parseMethodParams } from './function-parser'; import { containsModifier, getDefaultResourceIdentifier, getNodeType, isNodeDefaultExported, isNodeExported, } from './parse-utilities'; /** * Parses an interface node into its declaration. * Calculates the property and method defintions of the interface as well. * * @export * @param {Resource} resource * @param {InterfaceDeclaration} node */ export function parseInterface(resource: Resource, node: InterfaceDeclaration): void { const name = node.name ? node.name.text : getDefaultResourceIdentifier(resource); const interfaceDeclaration = new TshInterface( name, isNodeExported(node), node.getStart(), node.getEnd(), ); if (isNodeDefaultExported(node)) { interfaceDeclaration.isExported = false; resource.declarations.push(new DefaultDeclaration(interfaceDeclaration.name, resource)); } if (node.members) { node.members.forEach((o) => { if (isPropertySignature(o)) { interfaceDeclaration.properties.push( new PropertyDeclaration( (o.name as Identifier).text, DeclarationVisibility.Public, getNodeType(o.type), !!o.questionToken, containsModifier(o, SyntaxKind.StaticKeyword), o.getStart(), o.getEnd(), ), ); } else if (isMethodSignature(o)) { const method = new MethodDeclaration( (o.name as Identifier).text, true, DeclarationVisibility.Public, getNodeType(o.type), !!o.questionToken, containsModifier(o, SyntaxKind.StaticKeyword), containsModifier(o, SyntaxKind.AsyncKeyword), o.getStart(), o.getEnd(), ); method.parameters = parseMethodParams(o); interfaceDeclaration.methods.push(method); } }); } if (node.typeParameters) { interfaceDeclaration.typeParameters = node.typeParameters.map(param => param.getText()); } resource.declarations.push(interfaceDeclaration); } ================================================ FILE: src/node-parser/module-parser.ts ================================================ import { Identifier, ModuleDeclaration, NodeFlags } from 'typescript'; import { Module } from '../resources/Module'; import { Namespace } from '../resources/Namespace'; import { Resource } from '../resources/Resource'; /** * Parse a module to its declaration. Create a new namespace or module declaration and return it to * be used as the new "container". * * @export * @param {Resource} resource * @param {ModuleDeclaration} node * @returns {Resource} */ export function parseModule(resource: Resource, node: ModuleDeclaration): Resource { const newResource = (node.flags & NodeFlags.Namespace) === NodeFlags.Namespace ? new Namespace((node.name as Identifier).text, node.getStart(), node.getEnd()) : new Module((node.name as Identifier).text, node.getStart(), node.getEnd()); resource.resources.push(newResource); return newResource; } ================================================ FILE: src/node-parser/parse-utilities.ts ================================================ import { Declaration, getCombinedModifierFlags, ModifierFlags, Node, SyntaxKind, TypeNode } from 'typescript'; import { DeclarationVisibility } from '../declarations/DeclarationVisibility'; import { File } from '../resources/File'; import { Resource } from '../resources/Resource'; /** * Checks if the given typescript node has the exported flag. * (e.g. export class Foobar). * * @export * @param {Node} node * @returns {boolean} */ export function isNodeExported(node: Node): boolean { const flags = getCombinedModifierFlags(node as Declaration); return (flags & ModifierFlags.Export) === ModifierFlags.Export; } /** * Checks if the given typescript node has the default flag. * (e.g. export default class Foobar). * * @export * @param {Node} node * @returns {boolean} */ export function isNodeDefaultExported(node: Node): boolean { const flags = getCombinedModifierFlags(node as Declaration); return (flags & ModifierFlags.Default) === ModifierFlags.Default; } /** * Returns the type text (type information) for a given node. * * @export * @param {(TypeNode | undefined)} node * @returns {(string | undefined)} */ export function getNodeType(node: TypeNode | undefined): string | undefined { return node ? node.getText() : undefined; } /** * Checks if a node contains a certain modifier (of a given kind) * * @export * @param {Node} node * @param {SyntaxKind} modifierKind * @returns {boolean} */ export function containsModifier(node: Node, modifierKind: SyntaxKind): boolean { if (!node.modifiers) return false; return node.modifiers.some(mod => mod.kind === modifierKind); } /** * Returns the enum value (visibility) of a node. * * @export * @param {Node} node * @returns {(DeclarationVisibility | undefined)} */ export function getNodeVisibility(node: Node): DeclarationVisibility | undefined { if (!node.modifiers) { return undefined; } for (const modifier of node.modifiers) { switch (modifier.kind) { case SyntaxKind.PublicKeyword: return DeclarationVisibility.Public; case SyntaxKind.ProtectedKeyword: return DeclarationVisibility.Protected; case SyntaxKind.PrivateKeyword: return DeclarationVisibility.Private; default: break; } } } /** * Function that calculates the default name of a resource. * This is used when a default export has no name (i.e. export class {}). * * @export * @param {TsResource} resource * @returns {string} */ export function getDefaultResourceIdentifier(resource: Resource): string { if (resource instanceof File && resource.isWorkspaceFile) { return resource.parsedPath.name; } return resource.identifier; } ================================================ FILE: src/node-parser/traverse-ast.ts ================================================ export function traverseAst(root: Node, visit: (node: Node) => void, skipContents?: (node: Node) => boolean): void { const stack = (root as any).getChildren(); for (let node = stack.shift(); node !== undefined; node = stack.shift()) { visit(node); if (skipContents && skipContents(node)) { continue; } stack.unshift(...node.getChildren()); } } ================================================ FILE: src/node-parser/type-alias-parser.ts ================================================ import { TypeAliasDeclaration } from 'typescript'; import { TypeAliasDeclaration as TshType } from '../declarations/TypeAliasDeclaration'; import { Resource } from '../resources/Resource'; import { isNodeExported } from './parse-utilities'; /** * Parses a type alias into the declaration. * * @export * @param {Resource} resource * @param {TypeAliasDeclaration} node */ export function parseTypeAlias(resource: Resource, node: TypeAliasDeclaration): void { resource.declarations.push( new TshType(node.name.text, isNodeExported(node), node.getStart(), node.getEnd()), ); } ================================================ FILE: src/node-parser/variable-parser.ts ================================================ import { SyntaxKind, VariableStatement } from 'typescript'; import { CallableDeclaration } from '../declarations/Declaration'; import { VariableDeclaration } from '../declarations/VariableDeclaration'; import { Resource } from '../resources/Resource'; import { isCallableDeclaration } from '../type-guards/TypescriptHeroGuards'; import { getNodeType, isNodeExported } from './parse-utilities'; /** * Parse a variable. Information such as "is the variable const" are calculated here. * * @export * @param {(Resource | CallableDeclaration)} parent * @param {VariableStatement} node */ export function parseVariable(parent: Resource | CallableDeclaration, node: VariableStatement): void { const isConst = node.declarationList.getChildren().some(o => o.kind === SyntaxKind.ConstKeyword); if (node.declarationList && node.declarationList.declarations) { node.declarationList.declarations.forEach((o) => { const declaration = new VariableDeclaration( o.name.getText(), isConst, isNodeExported(node), getNodeType(o.type), node.getStart(), node.getEnd(), ); if (isCallableDeclaration(parent)) { parent.variables.push(declaration); } else { parent.declarations.push(declaration); } }); } } ================================================ FILE: src/resources/File.ts ================================================ import { parse, ParsedPath, relative } from 'path'; import { Declaration } from '../declarations/Declaration'; import { Export } from '../exports/Export'; import { Import } from '../imports/Import'; import { Node } from '../Node'; import { normalizeFilename } from '../utilities/PathHelpers'; import { Module } from './Module'; import { Namespace } from './Namespace'; import { Resource } from './Resource'; /** * TypeScript resource. Basically a file that is located somewhere. * * @export * @class File * @implements {Resource} * @implements {Node} */ export class File implements Resource, Node { public imports: Import[] = []; public exports: Export[] = []; public declarations: Declaration[] = []; public resources: Resource[] = []; public usages: string[] = []; public get identifier(): string { return '/' + normalizeFilename(relative(this.rootPath, this.filePath)); } public get nonLocalUsages(): string[] { return this.usages .filter(usage => !this.declarations.some(o => o.name === usage) && !this.resources.some(o => (o instanceof Module || o instanceof Namespace) && o.name === usage), ) .concat( this.resources.reduce((all, cur) => all.concat(cur.nonLocalUsages), [] as string[]), ); } /** * Returns the parsed path of a resource. * * @readonly * @type {ParsedPath} * @memberof File */ public get parsedPath(): ParsedPath { return parse(this.filePath); } /** * Determines if a file is a workspace file or an external resource. * * @readonly * @type {boolean} * @memberof File */ public get isWorkspaceFile(): boolean { return ['node_modules', 'typings'].every(o => this.filePath.indexOf(o) === -1); } constructor(public filePath: string, private rootPath: string, public start: number, public end: number) { } } ================================================ FILE: src/resources/Module.ts ================================================ import { Declaration } from '../declarations/Declaration'; import { Export } from '../exports/Export'; import { Import } from '../imports/Import'; import { Node } from '../Node'; import { Namespace } from './Namespace'; import { Resource } from './Resource'; /** * TypeScript resource. Declaration of a typescript module (i.e. declare module "foobar"). * * @export * @class Module * @implements {Resource} * @implements {Node} */ export class Module implements Resource, Node { public imports: Import[] = []; public exports: Export[] = []; public declarations: Declaration[] = []; public resources: Resource[] = []; public usages: string[] = []; public get identifier(): string { return this.name; } public get nonLocalUsages(): string[] { return this.usages .filter(usage => !this.declarations.some(o => o.name === usage) && !this.resources.some(o => (o instanceof Module || o instanceof Namespace) && o.name === usage)) .concat( this.resources.reduce((all, cur) => all.concat(cur.nonLocalUsages), [] as string[]), ); } constructor(public name: string, public start: number, public end: number) { } /** * Function that calculates the alias name of a namespace. * Removes all underlines and dashes and camelcases the name. * * @returns {string} * * @memberof Module */ public getNamespaceAlias(): string { return this.name.split(/[-_]/).reduce( (all, cur, idx) => { if (idx === 0) { return all + cur.toLowerCase(); } return all + cur.charAt(0).toUpperCase() + cur.substring(1).toLowerCase(); }, '', ); } } ================================================ FILE: src/resources/Namespace.ts ================================================ import { Declaration } from '../declarations/Declaration'; import { Export } from '../exports/Export'; import { Import } from '../imports/Import'; import { Node } from '../Node'; import { Module } from './Module'; import { Resource } from './Resource'; /** * TypeScript resource. Declaration of a typescript namespace (i.e. declare foobar). * * @export * @class Namespace * @implements {Resource} * @implements {Node} */ export class Namespace implements Resource, Node { public imports: Import[] = []; public exports: Export[] = []; public declarations: Declaration[] = []; public resources: Resource[] = []; public usages: string[] = []; public get identifier(): string { return this.name; } public get nonLocalUsages(): string[] { return this.usages .filter(usage => !this.declarations.some(o => o.name === usage) && !this.resources.some(o => (o instanceof Module || o instanceof Namespace) && o.name === usage)) .concat( this.resources.reduce((all, cur) => all.concat(cur.nonLocalUsages), [] as string[]), ); } constructor(public name: string, public start: number, public end: number) { } /** * Function that calculates the alias name of a namespace. * Removes all underlines and dashes and camelcases the name. * * @returns {string} * * @memberof Namespace */ public getNamespaceAlias(): string { return this.name.split(/[-_]/).reduce( (all, cur, idx) => { if (idx === 0) { return all + cur.toLowerCase(); } return all + cur.charAt(0).toUpperCase() + cur.substring(1).toLowerCase(); }, '', ); } } ================================================ FILE: src/resources/Resource.ts ================================================ import { Declaration } from '../declarations/Declaration'; import { Export } from '../exports/Export'; import { Import } from '../imports/Import'; /** * Base interface for resources. All resources share the same properties. * Resources are files, namespaces or modules. * * @export * @interface Resource */ export interface Resource { /** * List of imports contained in this resource. * * @type {Import[]} * @memberof Resource */ imports: Import[]; /** * List of exports contained in this resource. * * @type {Export[]} * @memberof Resource */ exports: Export[]; /** * List of declarations that are contained in this resource. * * @type {Declaration[]} * @memberof Resource */ declarations: Declaration[]; /** * List of subresources (like namespaces in a file) of this resource. * * @type {Resource[]} * @memberof Resource */ resources: Resource[]; /** * List of used identifiers in this resource. * (i.e. actual used string identifiers to calculate missing imports and stuff.) * * @type {string[]} * @memberof Resource */ usages: string[]; /** * "Unique" identifier for this resource. Can be the filepath for files or * node identifiers for node modules. * * @type {string} * @memberof Resource */ readonly identifier: string; /** * Returns an array of usages (a usage is a used symbol name in the resource) * that are not covered by its own declarations. * * @type {string[]} * @memberof Resource */ readonly nonLocalUsages: string[]; } ================================================ FILE: src/resources/index.ts ================================================ export * from './File'; export * from './Module'; export * from './Namespace'; export * from './Resource'; ================================================ FILE: src/type-guards/TypescriptGuards.ts ================================================ import { ArrayBindingPattern, ConstructorDeclaration, ExportDeclaration, ExternalModuleReference, FunctionDeclaration, GetAccessorDeclaration, Identifier, ImportDeclaration, ImportEqualsDeclaration, MethodDeclaration, MethodSignature, NamedExports, NamedImports, NamespaceImport, Node, ObjectBindingPattern, PropertyDeclaration, PropertySignature, SetAccessorDeclaration, StringLiteral, SyntaxKind, } from 'typescript'; /** * Determines if the given node is an ImportDeclaration. * * @export * @param {Node} [node] * @returns {node is ImportDeclaration} */ export function isImportDeclaration(node?: Node): node is ImportDeclaration { return node !== undefined && node.kind === SyntaxKind.ImportDeclaration; } /** * Determines if the given node is an ImportEqualsDeclaration. * * @export * @param {Node} [node] * @returns {node is ImportEqualsDeclaration} */ export function isImportEqualsDeclaration(node?: Node): node is ImportEqualsDeclaration { return node !== undefined && node.kind === SyntaxKind.ImportEqualsDeclaration; } /** * Determines if the given node is a NamespaceImport. * * @export * @param {Node} [node] * @returns {node is NamespaceImport} */ export function isNamespaceImport(node?: Node): node is NamespaceImport { return node !== undefined && node.kind === SyntaxKind.NamespaceImport; } /** * Determines if the given node are NamedImports. * * @export * @param {Node} [node] * @returns {node is NamedImports} */ export function isNamedImports(node?: Node): node is NamedImports { return node !== undefined && node.kind === SyntaxKind.NamedImports; } /** * Determines if the given node are NamedExports. * * @export * @param {Node} [node] * @returns {node is NamedExports} */ export function isNamedExports(node?: Node): node is NamedExports { return node !== undefined && node.kind === SyntaxKind.NamedExports; } /** * Determines if the given node is a StringLiteral. * * @export * @param {Node} [node] * @returns {node is StringLiteral} */ export function isStringLiteral(node?: Node): node is StringLiteral { return node !== undefined && node.kind === SyntaxKind.StringLiteral; } /** * Determines if the given node is an Identifier. * * @export * @param {Node} [node] * @returns {node is Identifier} */ export function isIdentifier(node?: Node): node is Identifier { return node !== undefined && node.kind === SyntaxKind.Identifier; } /** * Determines if the given node is an ExternalModuleReference. * * @export * @param {Node} [node] * @returns {node is ExternalModuleReference} */ export function isExternalModuleReference(node?: Node): node is ExternalModuleReference { return node !== undefined && node.kind === SyntaxKind.ExternalModuleReference; } /** * Determines if the given node is an ExportDeclaration. * * @export * @param {Node} [node] * @returns {node is ExportDeclaration} */ export function isExportDeclaration(node?: Node): node is ExportDeclaration { return node !== undefined && node.kind === SyntaxKind.ExportDeclaration; } /** * Determines if the given node is an ObjectBindingPattern (i.e. let {x, y} = foo). * * @export * @param {Node} [node] * @returns {node is ObjectBindingPattern} */ export function isObjectBindingPattern(node?: Node): node is ObjectBindingPattern { return node !== undefined && node.kind === SyntaxKind.ObjectBindingPattern; } /** * Determines if the given node is an ArrayBindingPattern (i.e. let [x, y] = foo). * * @export * @param {Node} [node] * @returns {node is ArrayBindingPattern} */ export function isArrayBindingPattern(node?: Node): node is ArrayBindingPattern { return node !== undefined && node.kind === SyntaxKind.ArrayBindingPattern; } /** * Determines if the given node is a FunctionDeclaration. * * @export * @param {Node} [node] * @returns {node is FunctionDeclaration} */ export function isFunctionDeclaration(node?: Node): node is FunctionDeclaration { return node !== undefined && node.kind === SyntaxKind.FunctionDeclaration; } /** * Determines if the given node is a MethodSignature. * * @export * @param {Node} [node] * @returns {node is MethodSignature} */ export function isMethodSignature(node?: Node): node is MethodSignature { return node !== undefined && node.kind === SyntaxKind.MethodSignature; } /** * Determines if the given node is a PropertySignature. * * @export * @param {Node} [node] * @returns {node is PropertySignature} */ export function isPropertySignature(node?: Node): node is PropertySignature { return node !== undefined && node.kind === SyntaxKind.PropertySignature; } /** * Determines if the given node is a MethodDeclaration. * * @export * @param {Node} [node] * @returns {node is MethodDeclaration} */ export function isMethodDeclaration(node?: Node): node is MethodDeclaration { return node !== undefined && node.kind === SyntaxKind.MethodDeclaration; } /** * Determines if the given node is a PropertyDeclaration. * * @export * @param {Node} [node] * @returns {node is PropertyDeclaration} */ export function isPropertyDeclaration(node?: Node): node is PropertyDeclaration { return node !== undefined && node.kind === SyntaxKind.PropertyDeclaration; } /** * Determines if the given node is a ConstructorDeclaration. * * @export * @param {Node} [node] * @returns {node is ConstructorDeclaration} */ export function isConstructorDeclaration(node?: Node): node is ConstructorDeclaration { return node !== undefined && node.kind === SyntaxKind.Constructor; } /** * Determines if the given node is a isGetAccessorDeclaration. * * @export * @param {Node} [node] * @returns {node is isGetAccessorDeclaration} */ export function isGetAccessorDeclaration(node?: Node): node is GetAccessorDeclaration { return node !== undefined && node.kind === SyntaxKind.GetAccessor; } /** * Determines if the given node is a SetAccessorDeclaration. * * @export * @param {Node} [node] * @returns {node is SetAccessorDeclaration} */ export function isSetAccessorDeclaration(node?: Node): node is SetAccessorDeclaration { return node !== undefined && node.kind === SyntaxKind.SetAccessor; } ================================================ FILE: src/type-guards/TypescriptHeroGuards.ts ================================================ import { CallableDeclaration, ExportableDeclaration } from '../declarations/Declaration'; import { AliasedImport } from '../imports/Import'; /** * Determines if the given object is a CallableDeclaration. * * @export * @param {*} obj * @returns {obj is CallableDeclaration} */ export function isCallableDeclaration(obj: any): obj is CallableDeclaration { return obj && obj.parameters && obj.variables; } /** * Determines if the given object is an ExportableDeclaration. * * @export * @param {*} obj * @returns {obj is ExportableDeclaration} */ export function isExportableDeclaration(obj: any): obj is ExportableDeclaration { return obj && Object.keys(obj).indexOf('isExported') >= 0; } /** * Determines if the given object is an AliasedImport. * * @export * @param {*} obj * @returns {obj is AliasedImport} */ export function isAliasedImport(obj: any): obj is AliasedImport { return obj && Object.keys(obj).indexOf('alias') >= 0; } ================================================ FILE: src/utilities/PathHelpers.ts ================================================ import { platform } from 'os'; /** * Returns a normalized version of the a path uri. Removes a "file://" or "file:///" prefix and removes semicolons. * * @export * @param {string} uri * @returns {string} */ export function normalizePathUri(uri: string): string { const decoded = decodeURIComponent(uri); if (platform() === 'win32') { return decoded.replace('file:///', ''); } return decoded.replace('file://', ''); } /** * Returns an adjusted and normalized filepath to use within the index. * Essentially does remove `.tsx` `.ts` `.js` `.jsx` endings and other adjustments. * * @export * @param {string} filepath * @returns {string} */ export function normalizeFilename(filepath: string): string { return toPosix(filepath.replace(/([.]d)?[.](t|j)sx?$/g, '')); } /** * On Windows, replaces all backslash delimeters with forward slashes. * On other OSes, returns the path unmodified. */ export function toPosix(path: string): string { if (platform() === 'win32') { return path.replace(/\\/g, '/'); } return path; } ================================================ FILE: src/utilities/StringTemplate.ts ================================================ /** * Creates a template from an expression string. The template can then be used to infuse stuff into the template. * * @export * @param {string[]} strings * @param {...number[]} keys * @returns {(...values: any[]) => string} */ export function stringTemplate(strings: TemplateStringsArray, ...keys: number[]): (...values: any[]) => string { return (...values: any[]) => { const result = [strings[0]]; keys.forEach((key, idx) => { result.push(values[key], strings[idx + 1]); }); return result.join(''); }; } ================================================ FILE: test/SpecificUsageCases.spec.ts ================================================ import { TypescriptParser } from '../src'; import { getWorkspaceFile, rootPath } from './testUtilities'; describe('Specific usage cases', () => { const parser = new TypescriptParser(); describe('i18next with and without destructure', () => { it('should contain i18next reference in not destructured way', async () => { const file = getWorkspaceFile('specific-usage-cases/i18next-destructure/import-my-component.tsx'); const parsed = await parser.parseFile(file, rootPath); expect(parsed.usages).toMatchSnapshot(); }); it('should contain t reference in destructured way', async () => { const file = getWorkspaceFile('specific-usage-cases/i18next-destructure/destructure-my-component.tsx'); const parsed = await parser.parseFile(file, rootPath); expect(parsed.usages).toMatchSnapshot(); }); }); describe('get usage for directly reexported elements', () => { it('should contain imported elements in usages', async () => { const file = getWorkspaceFile('specific-usage-cases/reexport/reexport-import.ts'); const parsed = await parser.parseFile(file, rootPath); expect(parsed.exports).toMatchSnapshot(); expect(parsed.usages).toMatchSnapshot(); }); it('should contain imported default elements in usages', async () => { const file = getWorkspaceFile('specific-usage-cases/reexport/reexport-default.ts'); const parsed = await parser.parseFile(file, rootPath); expect(parsed.exports).toMatchSnapshot(); expect(parsed.usages).toMatchSnapshot(); }); }); }); ================================================ FILE: test/TypescriptParser.spec.ts ================================================ import { readFileSync } from 'fs'; import { ScriptKind } from 'typescript'; import { ClassDeclaration } from '../src/declarations/ClassDeclaration'; import { DeclarationVisibility } from '../src/declarations/DeclarationVisibility'; import { DefaultDeclaration } from '../src/declarations/DefaultDeclaration'; import { EnumDeclaration } from '../src/declarations/EnumDeclaration'; import { FunctionDeclaration } from '../src/declarations/FunctionDeclaration'; import { InterfaceDeclaration } from '../src/declarations/InterfaceDeclaration'; import { TypeAliasDeclaration } from '../src/declarations/TypeAliasDeclaration'; import { VariableDeclaration } from '../src/declarations/VariableDeclaration'; import { AllExport } from '../src/exports/AllExport'; import { AssignedExport } from '../src/exports/AssignedExport'; import { NamedExport } from '../src/exports/NamedExport'; import { ExternalModuleImport } from '../src/imports/ExternalModuleImport'; import { NamedImport } from '../src/imports/NamedImport'; import { NamespaceImport } from '../src/imports/NamespaceImport'; import { StringImport } from '../src/imports/StringImport'; import { File } from '../src/resources'; import { Module } from '../src/resources/Module'; import { Namespace } from '../src/resources/Namespace'; import { Resource } from '../src/resources/Resource'; import { TypescriptParser } from '../src/TypescriptParser'; import { getWorkspaceFile, rootPath } from './testUtilities'; describe('TypescriptParser', () => { let parser: TypescriptParser; beforeEach(() => { parser = new TypescriptParser(); }); describe('Source parsing', () => { it('should parse a source code string correctly', async () => { const parsed = await parser.parseSource(`import {foo} from 'bar'; class Foobar {}; const bar = new Foobar();`); expect(parsed).toMatchSnapshot(); }); }); describe('Import parsing', () => { const file = getWorkspaceFile('typescript-parser/importsOnly.ts'); let parsed: Resource; beforeEach(async () => { parsed = await parser.parseFile(file, rootPath); }); it('should parse imports', () => { expect(parsed.imports).toHaveLength(12); expect(parsed.imports).toMatchSnapshot(); }); it('should parse string import', () => { expect(parsed.imports[0]).toBeInstanceOf(StringImport); expect(parsed.imports[0]).toMatchSnapshot(); }); it('should parse named import', () => { expect(parsed.imports[1]).toBeInstanceOf(NamedImport); expect(parsed.imports[1]).toMatchSnapshot(); }); it('should parse named import with aliased specifier', () => { expect(parsed.imports[2]).toBeInstanceOf(NamedImport); expect(parsed.imports[2]).toMatchSnapshot(); }); it('should parse namespace import', () => { expect(parsed.imports[3]).toBeInstanceOf(NamespaceImport); expect(parsed.imports[3]).toMatchSnapshot(); }); it('should parse external module import', () => { expect(parsed.imports[4]).toBeInstanceOf(ExternalModuleImport); expect(parsed.imports[4]).toMatchSnapshot(); }); it('should parse a multiline import', () => { expect(parsed.imports[5]).toBeInstanceOf(NamedImport); expect(parsed.imports[5]).toMatchSnapshot(); }); it('should parse a default import', () => { expect(parsed.imports[6]).toBeInstanceOf(NamedImport); expect(parsed.imports[6]).toMatchSnapshot(); }); it('should not add any imports to the usages', () => { expect(parsed.usages).toHaveLength(0); }); it('should parse a named import with a default statement', () => { expect(parsed.imports[7]).toBeInstanceOf(NamedImport); expect(parsed.imports[7]).toMatchSnapshot(); }); it('should parse a mixed default / named import', () => { expect(parsed.imports[8]).toBeInstanceOf(NamedImport); expect(parsed.imports[8]).toMatchSnapshot(); }); it('should not parse a wrong default statement', async () => { const wrong = await parser.parseSource(`import { default } from 'myLib';`); expect(wrong).toBeInstanceOf(File); expect(wrong).toMatchSnapshot(); }); }); describe('Export parsing', () => { const file = getWorkspaceFile('typescript-parser/exportsOnly.ts'); let parsed: Resource; beforeEach(async () => { parsed = await parser.parseFile(file, rootPath); }); it('should parse export all from another file', () => { expect(parsed.exports[0]).toBeInstanceOf(AllExport); expect(parsed.exports[0]).toMatchSnapshot(); }); it('should parse export named from another file', () => { expect(parsed.exports[1]).toBeInstanceOf(NamedExport); expect(parsed.exports[1]).toMatchSnapshot(); }); it('should parse aliased export named from another file', () => { expect(parsed.exports[1]).toBeInstanceOf(NamedExport); expect((parsed.exports[1] as NamedExport).specifiers[1]).toMatchSnapshot(); }); it('should parse export assignment', () => { expect(parsed.exports[2]).toBeInstanceOf(AssignedExport); delete (parsed.exports[2] as any).resource.filePath; delete (parsed.exports[2] as any).resource.rootPath; expect(parsed.exports[2]).toMatchSnapshot(); }); it('should parse default export', () => { expect(parsed.declarations[0]).toBeInstanceOf(DefaultDeclaration); delete (parsed.declarations[0] as any).resource.filePath; delete (parsed.declarations[0] as any).resource.rootPath; expect(parsed.declarations[0]).toMatchSnapshot(); }); }); describe('Declaration parsing', () => { describe('Enums', () => { const file = getWorkspaceFile('typescript-parser/enum.ts'); let parsed: Resource; beforeEach(async () => { parsed = await parser.parseFile(file, rootPath); }); it('should parse a file', () => { expect(parsed.declarations).toHaveLength(2); }); it('should parse an enum correctly', () => { expect(parsed.declarations[0]).toBeInstanceOf(EnumDeclaration); expect(parsed.declarations[0]).toMatchSnapshot(); }); it('should parse an exported enum correctly', () => { expect(parsed.declarations[1]).toBeInstanceOf(EnumDeclaration); expect(parsed.declarations[1]).toMatchSnapshot(); }); }); describe('Type aliases', () => { const file = getWorkspaceFile('typescript-parser/typeAlias.ts'); let parsed: Resource; beforeEach(async () => { parsed = await parser.parseFile(file, rootPath); }); it('should parse a file', () => { expect(parsed.declarations).toHaveLength(2); }); it('should parse a type alias correctly', () => { expect(parsed.declarations[0]).toBeInstanceOf(TypeAliasDeclaration); expect(parsed.declarations[0]).toMatchSnapshot(); }); it('should parse an exported type alias correctly', () => { expect(parsed.declarations[1]).toBeInstanceOf(TypeAliasDeclaration); expect(parsed.declarations[1]).toMatchSnapshot(); }); }); describe('Functions', () => { const file = getWorkspaceFile('typescript-parser/function.ts'); let parsed: Resource; beforeEach(async () => { parsed = await parser.parseFile(file, rootPath); }); it('should parse a file', () => { expect(parsed.declarations).toHaveLength(4); }); it('should parse a function correctly', () => { expect(parsed.declarations[0]).toBeInstanceOf(FunctionDeclaration); expect(parsed.declarations[0]).toMatchSnapshot(); }); it('should parse an exported function correctly', () => { expect(parsed.declarations[1]).toBeInstanceOf(FunctionDeclaration); expect(parsed.declarations[1]).toMatchSnapshot(); }); it('should parse parameters correctly', () => { expect((parsed.declarations[0] as FunctionDeclaration).parameters).toMatchSnapshot(); expect((parsed.declarations[1] as FunctionDeclaration).parameters).toMatchSnapshot(); }); it('should parse variables correctly', () => { expect((parsed.declarations[0] as FunctionDeclaration).variables).toMatchSnapshot(); expect((parsed.declarations[1] as FunctionDeclaration).variables).toMatchSnapshot(); }); it('should parse return types correctly', () => { expect((parsed.declarations[0] as FunctionDeclaration).type).toBe('string'); expect((parsed.declarations[1] as FunctionDeclaration).type).toBe('void'); expect((parsed.declarations[2] as FunctionDeclaration).type).toBeUndefined(); }); it('should parse a typeguard correctly', () => { expect((parsed.declarations[3] as FunctionDeclaration).type).toBe('str is number'); }); }); describe('Parameters', () => { const file = getWorkspaceFile('typescript-parser/parameters.ts'); let parsed: Resource; beforeEach(async () => { parsed = await parser.parseFile(file, rootPath); }); it('should parse a normal parameter', () => { const func = parsed.declarations[0] as FunctionDeclaration; expect(func.parameters[0]).toMatchSnapshot(); }); it('should parse a simple array binding pattern', () => { const func = parsed.declarations[1] as FunctionDeclaration; expect(func.parameters[0]).toMatchSnapshot(); }); it('should parse an array with tuple type', () => { const func = parsed.declarations[2] as FunctionDeclaration; expect(func.parameters[0]).toMatchSnapshot(); }); it('should parse an array with undertyped tuple type', () => { const func = parsed.declarations[3] as FunctionDeclaration; expect(func.parameters[0]).toMatchSnapshot(); }); it('should parse an array with overtyped tuple type', () => { const func = parsed.declarations[4] as FunctionDeclaration; expect(func.parameters[0]).toMatchSnapshot(); }); it('should parse a simple object binding pattern ', () => { const func = parsed.declarations[5] as FunctionDeclaration; expect(func.parameters[0]).toMatchSnapshot(); }); it('should parse an object with type reference', () => { const func = parsed.declarations[6] as FunctionDeclaration; expect(func.parameters[0]).toMatchSnapshot(); }); it('should parse an object with type literal', () => { const func = parsed.declarations[7] as FunctionDeclaration; expect(func.parameters[0]).toMatchSnapshot(); }); it('should parse an object with undertyped type literal', () => { const func = parsed.declarations[8] as FunctionDeclaration; expect(func.parameters[0]).toMatchSnapshot(); }); it('should parse an object with overtyped type literal', () => { const func = parsed.declarations[9] as FunctionDeclaration; expect(func.parameters[0]).toMatchSnapshot(); }); it('should parse some mixed parameters (all above)', () => { expect(parsed.declarations[10]).toMatchSnapshot(); }); it('should generate the correct name for an object', () => { const func = parsed.declarations[9] as FunctionDeclaration; expect(func.parameters[0].name).toMatchSnapshot(); }); it('should generate the correct name for an array', () => { const func = parsed.declarations[2] as FunctionDeclaration; expect(func.parameters[0].name).toMatchSnapshot(); }); it('should generate the correct type for an object', () => { const func = parsed.declarations[9] as FunctionDeclaration; expect(func.parameters[0].type).toMatchSnapshot(); }); it('should generate the correct type for an array', () => { const func = parsed.declarations[2] as FunctionDeclaration; expect(func.parameters[0].type).toMatchSnapshot(); }); }); describe('Variables', () => { const file = getWorkspaceFile('typescript-parser/variable.ts'); let parsed: Resource; beforeEach(async () => { parsed = await parser.parseFile(file, rootPath); }); it('should parse a file', () => { expect(parsed.declarations).toHaveLength(7); }); it('should parse a non exported variable', () => { expect(parsed.declarations[0]).toBeInstanceOf(VariableDeclaration); expect(parsed.declarations[0]).toMatchSnapshot(); }); it('should parse a non exported const', () => { expect(parsed.declarations[1]).toBeInstanceOf(VariableDeclaration); expect(parsed.declarations[1]).toMatchSnapshot(); }); it('should parse an exported variable', () => { expect(parsed.declarations[2]).toBeInstanceOf(VariableDeclaration); expect(parsed.declarations[2]).toMatchSnapshot(); }); it('should parse an exported const', () => { expect(parsed.declarations[3]).toBeInstanceOf(VariableDeclaration); expect(parsed.declarations[3]).toMatchSnapshot(); }); it('should parse an exported scope variable', () => { expect(parsed.declarations[4]).toBeInstanceOf(VariableDeclaration); expect(parsed.declarations[4]).toMatchSnapshot(); }); it('should parse an exported multiline variable', () => { expect(parsed.declarations[5]).toBeInstanceOf(VariableDeclaration); expect(parsed.declarations[5]).toMatchSnapshot(); expect(parsed.declarations[6]).toBeInstanceOf(VariableDeclaration); expect(parsed.declarations[6]).toMatchSnapshot(); }); }); describe('Interfaces', () => { const file = getWorkspaceFile('typescript-parser/interface.ts'); let parsed: Resource; beforeEach(async () => { parsed = await parser.parseFile(file, rootPath); }); it('should parse a file', () => { expect(parsed.declarations).toHaveLength(6); }); it('should parse a non exported interface', () => { expect(parsed.declarations[0]).toBeInstanceOf(InterfaceDeclaration); expect(parsed.declarations[0]).toMatchSnapshot(); }); it('should parse an exported interface', () => { expect(parsed.declarations[1]).toBeInstanceOf(InterfaceDeclaration); expect(parsed.declarations[1]).toMatchSnapshot(); }); it('should parse the returntype of a method', () => { const parsedInterface = parsed.declarations[0] as InterfaceDeclaration; expect(parsedInterface.methods[0].type).toBeUndefined(); expect(parsedInterface.methods[1].type).toBe('void'); }); it('should parse the type of a property', () => { const parsedInterface = parsed.declarations[1] as InterfaceDeclaration; expect(parsedInterface.properties[0].type).toBe('string'); expect(parsedInterface.properties[1].type).toBe('number'); }); it('should parse a generic interface', () => { const parsedInterface = parsed.declarations[2] as InterfaceDeclaration; expect(parsedInterface.typeParameters).toContain('T'); }); it('should parse a generic interface with multiple type params', () => { const parsedInterface = parsed.declarations[3] as InterfaceDeclaration; expect(parsedInterface.typeParameters).toContain('TIn'); expect(parsedInterface.typeParameters).toContain('TOut'); expect(parsedInterface.typeParameters).toContain('TError'); }); it('should parse optional properties', () => { const parsedInterface = parsed.declarations[4] as InterfaceDeclaration; expect(parsedInterface.properties).toMatchSnapshot(); }); it('should parse optional functions', () => { const parsedInterface = parsed.declarations[5] as InterfaceDeclaration; expect(parsedInterface).toMatchSnapshot(); }); }); describe('Classes', () => { const file = getWorkspaceFile('typescript-parser/class.ts'); let parsed: Resource; beforeEach(async () => { parsed = await parser.parseFile(file, rootPath); }); it('should parse a file', () => { expect(parsed.declarations).toHaveLength(10); }); it('should parse an abstract class', () => { expect(parsed.declarations[0]).toBeInstanceOf(ClassDeclaration); expect(parsed.declarations[0]).toMatchSnapshot(); }); it('should parse a non exported class', () => { expect(parsed.declarations[1]).toBeInstanceOf(ClassDeclaration); expect(parsed.declarations[1]).toMatchSnapshot(); }); it('should parse an exported class', () => { expect(parsed.declarations[2]).toBeInstanceOf(ClassDeclaration); expect(parsed.declarations[2]).toMatchSnapshot(); }); it('should parse the returntype of a method', () => { const parsedClass = parsed.declarations[0] as ClassDeclaration; expect(parsedClass.methods[0].type).toBeUndefined(); expect(parsedClass.methods[1].type).toBe('void'); }); it('should parse the type of a property', () => { const parsedClass = parsed.declarations[2] as ClassDeclaration; expect(parsedClass.properties[0].type).toBe('string'); }); it('should parse the type of a constructor introduced property', () => { const parsedClass = parsed.declarations[1] as ClassDeclaration; expect(parsedClass.properties[0].type).toBe('string'); }); it('should parse a methods visibility', () => { const parsedClass = parsed.declarations[1] as ClassDeclaration; expect(parsedClass.methods[0].visibility).toBe(DeclarationVisibility.Public); }); it('should parse a generic class', () => { const parsedClass = parsed.declarations[3] as ClassDeclaration; expect(parsedClass.typeParameters).toContain('T'); }); it('should parse a generic class with multiple type params', () => { const parsedClass = parsed.declarations[4] as ClassDeclaration; expect(parsedClass.typeParameters).toContain('TIn'); expect(parsedClass.typeParameters).toContain('TOut'); expect(parsedClass.typeParameters).toContain('TError'); }); it('should parse property accessors', () => { const parsedClass = parsed.declarations[5] as ClassDeclaration; expect(parsedClass.accessors).toMatchSnapshot(); }); it('should parse abstract property accessors', () => { const parsedClass = parsed.declarations[6] as ClassDeclaration; expect(parsedClass.accessors).toMatchSnapshot(); }); it('should parse object and array destructure pattern in a class method', () => { const parsedClass = parsed.declarations[7] as ClassDeclaration; expect(parsedClass.methods).toMatchSnapshot(); }); it('should parse object and array destructure pattern in a class constructor', () => { const parsedClass = parsed.declarations[7] as ClassDeclaration; expect(parsedClass.ctor).toMatchSnapshot(); }); it('should parse optional class properties', () => { const parsedClass = parsed.declarations[8] as ClassDeclaration; expect(parsedClass.properties).toMatchSnapshot(); }); it('should parse static class properties and methods', () => { const parsedClass = parsed.declarations[9] as ClassDeclaration; expect(parsedClass).toMatchSnapshot(); }); }); describe('Modules', () => { const file = getWorkspaceFile('typescript-parser/module.ts'); let parsed: Resource; beforeEach(async () => { parsed = await parser.parseFile(file, rootPath); }); it('should parse a file', () => { expect(parsed.resources).toHaveLength(2); }); it('should parse a module', () => { expect(parsed.resources[0]).toBeInstanceOf(Module); expect(parsed.resources[0]).toMatchSnapshot(); }); it('should parse a namespace', () => { expect(parsed.resources[1]).toBeInstanceOf(Namespace); expect(parsed.resources[1]).toMatchSnapshot(); }); }); }); describe('Usage parsing', () => { const file = getWorkspaceFile('typescript-parser/usagesOnly.ts'); let parsed: Resource; beforeEach(async () => { parsed = await parser.parseFile(file, rootPath); }); it('should parse decorator usages', () => { const usages = parsed.usages; expect(usages).toContain('ClassDecorator'); expect(usages).toContain('PropertyDecorator'); expect(usages).toContain('FunctionDecorator'); expect(usages).toContain('ParamDecorator'); }); it('should parse class member', () => { const usages = parsed.usages; expect(usages).toContain('notInitializedProperty'); expect(usages).toContain('typedProperty'); }); it('should parse class member types', () => { const usages = parsed.usages; expect(usages).toContain('TypedPropertyRef'); }); it('should parse class member assignment', () => { const usages = parsed.usages; expect(usages).toContain('AssignedProperty'); }); it('should parse params', () => { const usages = parsed.usages; expect(usages).toContain('param'); }); it('should parse param default assignment', () => { const usages = parsed.usages; expect(usages).toContain('DefaultParam'); }); it('should parse return value', () => { const usages = parsed.usages; expect(usages).toContain('ReturnValue'); }); it('should parse property access', () => { const usages = parsed.usages; expect(usages).toContain('PropertyAccess'); }); it('should not parse sub properties of accessed properties', () => { const usages = parsed.usages; expect(usages).not.toContain('To'); expect(usages).not.toContain('My'); expect(usages).not.toContain('Foobar'); }); it('should parse function call', () => { const usages = parsed.usages; expect(usages).toContain('functionCall'); expect(usages).toContain('MyProperty'); }); it('should parse indexer access', () => { const usages = parsed.usages; expect(usages).toContain('Indexing'); }); it('should parse variable assignment', () => { const usages = parsed.usages; expect(usages).toContain('AssignmentToVariable'); }); it('should parse nested identifier', () => { const usages = parsed.usages; expect(usages).toContain('NestedBinaryAssignment'); }); it('should parse a global (file level) used function', () => { const usages = parsed.usages; expect(usages).toContain('globalFunction'); }); it('should parse a global extended class', () => { const usages = parsed.usages; expect(usages).toContain('DefaultClass'); }); it('should parse a generic identifier in a class extension', () => { const usages = parsed.usages; expect(usages).toContain('GenericType'); }); it('should parse a default exported element', () => { const usages = parsed.usages; expect(usages).toContain('defaultExportUsage'); }); it('should parse an indexer property', () => { const usages = parsed.usages; expect(usages).toContain('indexedUsage'); }); it('should parse an indexer property access', () => { const usages = parsed.usages; expect(usages).toContain('indexingUsage'); }); }); describe('TSX Usage parsing', () => { const file = getWorkspaceFile('typescript-parser/usagesOnly.tsx'); let parsed: Resource; beforeEach(async () => { parsed = await parser.parseFile(file, rootPath); }); it('should parse a tsx element usage', () => { const usages = parsed.usages; expect(usages).toContain('myComponent'); expect(usages).toContain('div'); expect(usages).toContain('complexComp'); expect(usages).toContain('SingleComp'); }); it('should parse functions inside {}', () => { const usages = parsed.usages; expect(usages).toContain('myFunc'); }); it('should parse component functions inside {}', () => { const usages = parsed.usages; expect(usages).toContain('MyFunc'); }); it('should parse a component inside a map', () => { const usages = parsed.usages; expect(usages).toContain('AnotherComp'); expect(usages).toContain('foobarVariable'); }); it('should parse a function inside a map', () => { const usages = parsed.usages; expect(usages).toContain('valFunc'); }); it('should parseSource correctly', async () => { const parsedSource = await parser.parseSource(readFileSync(file).toString(), ScriptKind.TSX); expect(parsedSource.usages).toMatchSnapshot(); }); }); describe('TSX: Specific cases', () => { const testFiles = [ { filename: '1.tsx', requiredUsages: [ 'sortBy', 'Divider', 'Checkbox', ], }, { filename: '2.tsx', requiredUsages: [ 'ActionDelete', 'Divider', 'cloneDeep', ], }, { filename: '3.tsx', requiredUsages: [ 'ImageEdit', 'IconButton', 'TableHeaderColumn', ], }, ]; for (const testFile of testFiles) { it('should parse the correct usages with "parseFile"', async () => { const file = getWorkspaceFile(`typescript-parser/specific-cases/${testFile.filename}`); const parsed = await parser.parseFile(file, rootPath); for (const usage of testFile.requiredUsages) { expect(parsed.usages).toContain(usage); } expect(parsed.usages).toMatchSnapshot(); }); it('should parse the correct usages with "parseFiles"', async () => { const file = getWorkspaceFile(`typescript-parser/specific-cases/${testFile.filename}`); const parsed = (await parser.parseFiles([file], rootPath))[0]; for (const usage of testFile.requiredUsages) { expect(parsed.usages).toContain(usage); } expect(parsed.usages).toMatchSnapshot(); }); it('should parse the correct usages with "parseSource"', async () => { const file = getWorkspaceFile(`typescript-parser/specific-cases/${testFile.filename}`); const fileSource = readFileSync(file).toString(); const parsed = await parser.parseSource(fileSource, ScriptKind.TSX); for (const usage of testFile.requiredUsages) { expect(parsed.usages).toContain(usage); } expect(parsed.usages).toMatchSnapshot(); }); } }); describe('JavaScript parsing', () => { const file = getWorkspaceFile('typescript-parser/javascript.js'); it('should parse a simple javascript file correctly with "parseFile"', async () => { const parsed = await parser.parseFile(file, rootPath); delete parsed.filePath; delete (parsed as any).rootPath; expect(parsed).toMatchSnapshot(); }); it('should parse a simple javascript file correctly with "parseFiles"', async () => { const parsed = await parser.parseFiles([file], rootPath); delete parsed[0].filePath; delete (parsed[0] as any).rootPath; expect(parsed).toMatchSnapshot(); }); it('should parse a simple javascript file correctly with "parseSource"', async () => { const content = readFileSync(file).toString(); const parsed = await parser.parseSource(content, ScriptKind.JS); expect(parsed).toMatchSnapshot(); }); }); describe('JSX parsing', () => { const file = getWorkspaceFile('typescript-parser/jsx.jsx'); it('should parse a simple javascript react file correctly with "parseFile"', async () => { const parsed = await parser.parseFile(file, rootPath); delete parsed.filePath; delete (parsed as any).rootPath; expect(parsed).toMatchSnapshot(); }); it('should parse a simple javascript react file correctly with "parseFiles"', async () => { const parsed = await parser.parseFiles([file], rootPath); delete parsed[0].filePath; delete (parsed[0] as any).rootPath; expect(parsed).toMatchSnapshot(); }); it('should parse a simple javascript react file correctly with "parseSource"', async () => { const content = readFileSync(file).toString(); const parsed = await parser.parseSource(content, ScriptKind.JSX); expect(parsed).toMatchSnapshot(); }); }); describe('Specific sources', () => { it('should parse generics in functions in classes correctly', async () => { const parsed = await parser.parseSource( `export class TestClass { public test() { let a = () => { let b = null; }; } }`, ScriptKind.TS, ); expect(parsed).toMatchSnapshot(); }); }); describe('Parses Webpack Bundle', () => { const file = getWorkspaceFile('typescript-parser/webpack-bundle.js'); it('should parse the whole webpack bundle', async () => { await parser.parseFile(file, rootPath); }); }); }); ================================================ FILE: test/__snapshots__/SpecificUsageCases.spec.ts.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Specific usage cases get usage for directly reexported elements should contain imported default elements in usages 1`] = `Array []`; exports[`Specific usage cases get usage for directly reexported elements should contain imported default elements in usages 2`] = ` Array [ "Test", ] `; exports[`Specific usage cases get usage for directly reexported elements should contain imported elements in usages 1`] = ` Array [ NamedExport { "end": 184, "from": "reexport-import", "specifiers": Array [ SymbolSpecifier { "alias": undefined, "specifier": "colors", }, SymbolSpecifier { "alias": undefined, "specifier": "helpers", }, SymbolSpecifier { "alias": undefined, "specifier": "theme", }, SymbolSpecifier { "alias": undefined, "specifier": "icons", }, ], "start": 143, }, ] `; exports[`Specific usage cases get usage for directly reexported elements should contain imported elements in usages 2`] = ` Array [ "colors", "helpers", "theme", "icons", ] `; exports[`Specific usage cases i18next with and without destructure should contain i18next reference in not destructured way 1`] = ` Array [ "MyComponent", "p", "i18next", ] `; exports[`Specific usage cases i18next with and without destructure should contain t reference in destructured way 1`] = ` Array [ "MyComponent", "p", "t", ] `; ================================================ FILE: test/__snapshots__/TypescriptParser.spec.ts.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`TypescriptParser Declaration parsing Classes should parse a non exported class 1`] = ` ClassDeclaration { "accessors": Array [], "ctor": ConstructorDeclaration { "end": 171, "name": "NonExportedClass", "parameters": Array [ ParameterDeclaration { "end": 166, "name": "param1", "start": 145, "type": "string", }, ], "start": 133, "variables": Array [], }, "end": 302, "isExported": false, "methods": Array [ MethodDeclaration { "end": 203, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "method1", "parameters": Array [], "start": 177, "type": "void", "variables": Array [], "visibility": 2, }, MethodDeclaration { "end": 237, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "method2", "parameters": Array [], "start": 208, "type": "void", "variables": Array [], "visibility": 1, }, MethodDeclaration { "end": 300, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "method3", "parameters": Array [], "start": 242, "type": "void", "variables": Array [ VariableDeclaration { "end": 294, "isConst": false, "isExported": false, "name": "variable", "start": 276, "type": undefined, }, ], "visibility": 0, }, ], "name": "NonExportedClass", "properties": Array [ PropertyDeclaration { "end": 166, "isOptional": false, "isStatic": false, "name": "param1", "start": 145, "type": "string", "visibility": 2, }, ], "start": 104, } `; exports[`TypescriptParser Declaration parsing Classes should parse abstract property accessors 1`] = ` Array [ GetterDeclaration { "end": 977, "isAbstract": true, "isStatic": false, "name": "getOnly", "start": 939, "type": "string", "visibility": 2, }, SetterDeclaration { "end": 1022, "isAbstract": true, "isStatic": false, "name": "setOnly", "start": 982, "type": undefined, "visibility": 2, }, GetterDeclaration { "end": 1067, "isAbstract": true, "isStatic": false, "name": "getAndSet", "start": 1027, "type": "string", "visibility": 2, }, SetterDeclaration { "end": 1117, "isAbstract": true, "isStatic": false, "name": "getAndSet", "start": 1072, "type": undefined, "visibility": 2, }, ] `; exports[`TypescriptParser Declaration parsing Classes should parse an abstract class 1`] = ` ClassDeclaration { "accessors": Array [], "end": 102, "isExported": false, "methods": Array [ MethodDeclaration { "end": 55, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "method1", "parameters": Array [], "start": 35, "type": undefined, "variables": Array [], "visibility": 2, }, MethodDeclaration { "end": 100, "isAbstract": true, "isAsync": false, "isOptional": false, "isStatic": false, "name": "abstractMethod", "parameters": Array [], "start": 61, "type": "void", "variables": Array [], "visibility": 2, }, ], "name": "AbstractClass", "properties": Array [], "start": 0, } `; exports[`TypescriptParser Declaration parsing Classes should parse an exported class 1`] = ` ClassDeclaration { "accessors": Array [ GetterDeclaration { "end": 492, "isAbstract": false, "isStatic": false, "name": "property", "start": 424, "type": "string", "visibility": 2, }, SetterDeclaration { "end": 572, "isAbstract": false, "isStatic": false, "name": "property", "start": 498, "type": undefined, "visibility": 2, }, ], "end": 574, "isExported": true, "methods": Array [], "name": "ExportedClass", "properties": Array [ PropertyDeclaration { "end": 363, "isOptional": false, "isStatic": false, "name": "_property", "start": 337, "type": "string", "visibility": 0, }, PropertyDeclaration { "end": 394, "isOptional": false, "isStatic": false, "name": "protect", "start": 368, "type": "string", "visibility": 1, }, PropertyDeclaration { "end": 418, "isOptional": false, "isStatic": false, "name": "pub", "start": 399, "type": "string", "visibility": 2, }, ], "start": 304, } `; exports[`TypescriptParser Declaration parsing Classes should parse object and array destructure pattern in a class constructor 1`] = ` ConstructorDeclaration { "end": 1198, "name": "ObjAndArrDestruct", "parameters": Array [ ParameterDeclaration { "end": 1167, "name": "p1", "start": 1165, "type": undefined, }, ParameterDeclaration { "end": 1171, "name": "p2", "start": 1169, "type": undefined, }, ParameterDeclaration { "end": 1183, "name": "p3", "start": 1181, "type": undefined, }, ParameterDeclaration { "end": 1187, "name": "p4", "start": 1185, "type": undefined, }, ], "start": 1151, "variables": Array [], } `; exports[`TypescriptParser Declaration parsing Classes should parse object and array destructure pattern in a class method 1`] = ` Array [ MethodDeclaration { "end": 1251, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "objMethod", "parameters": Array [ ObjectBoundParameterDeclaration { "end": 1240, "endCharacter": "}", "parameters": Array [ ParameterDeclaration { "end": 1225, "name": "p1", "start": 1223, "type": undefined, }, ParameterDeclaration { "end": 1229, "name": "p2", "start": 1227, "type": undefined, }, ParameterDeclaration { "end": 1233, "name": "p3", "start": 1231, "type": undefined, }, ], "start": 1221, "startCharacter": "{", }, ], "start": 1204, "type": "void", "variables": Array [], "visibility": 2, }, MethodDeclaration { "end": 1307, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "arrMethod", "parameters": Array [ ArrayBoundParameterDeclaration { "end": 1296, "endCharacter": "]", "parameters": Array [ ParameterDeclaration { "end": 1277, "name": "p1", "start": 1275, "type": undefined, }, ParameterDeclaration { "end": 1281, "name": "p2", "start": 1279, "type": undefined, }, ParameterDeclaration { "end": 1285, "name": "p3", "start": 1283, "type": undefined, }, ], "start": 1274, "startCharacter": "[", }, ], "start": 1257, "type": "void", "variables": Array [], "visibility": 2, }, MethodDeclaration { "end": 1386, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "objAndArrMethod", "parameters": Array [ ArrayBoundParameterDeclaration { "end": 1358, "endCharacter": "]", "parameters": Array [ ParameterDeclaration { "end": 1339, "name": "p1", "start": 1337, "type": undefined, }, ParameterDeclaration { "end": 1343, "name": "p2", "start": 1341, "type": undefined, }, ParameterDeclaration { "end": 1347, "name": "p3", "start": 1345, "type": undefined, }, ], "start": 1336, "startCharacter": "[", }, ObjectBoundParameterDeclaration { "end": 1375, "endCharacter": "}", "parameters": Array [ ParameterDeclaration { "end": 1364, "name": "p4", "start": 1362, "type": undefined, }, ParameterDeclaration { "end": 1368, "name": "p5", "start": 1366, "type": undefined, }, ], "start": 1360, "startCharacter": "{", }, ], "start": 1313, "type": "void", "variables": Array [], "visibility": 2, }, ] `; exports[`TypescriptParser Declaration parsing Classes should parse optional class properties 1`] = ` Array [ PropertyDeclaration { "end": 1448, "isOptional": false, "isStatic": false, "name": "nonOptional", "start": 1421, "type": "string", "visibility": 2, }, PropertyDeclaration { "end": 1498, "isOptional": false, "isStatic": false, "name": "nonOptionalAsWell", "start": 1453, "type": "string | undefined", "visibility": 2, }, PropertyDeclaration { "end": 1528, "isOptional": true, "isStatic": false, "name": "optional", "start": 1503, "type": "string", "visibility": 2, }, ] `; exports[`TypescriptParser Declaration parsing Classes should parse property accessors 1`] = ` Array [ GetterDeclaration { "end": 731, "isAbstract": false, "isStatic": false, "name": "getOnly", "start": 670, "type": "string", "visibility": 2, }, SetterDeclaration { "end": 775, "isAbstract": false, "isStatic": false, "name": "setOnly", "start": 737, "type": undefined, "visibility": 2, }, GetterDeclaration { "end": 838, "isAbstract": false, "isStatic": false, "name": "getAndSet", "start": 781, "type": "string", "visibility": 2, }, SetterDeclaration { "end": 888, "isAbstract": false, "isStatic": false, "name": "getAndSet", "start": 844, "type": undefined, "visibility": 2, }, ] `; exports[`TypescriptParser Declaration parsing Classes should parse static class properties and methods 1`] = ` ClassDeclaration { "accessors": Array [], "end": 1662, "isExported": false, "methods": Array [ MethodDeclaration { "end": 1621, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": true, "name": "method", "parameters": Array [], "start": 1589, "type": "void", "variables": Array [], "visibility": 2, }, MethodDeclaration { "end": 1660, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "methodNonStatic", "parameters": Array [], "start": 1626, "type": "void", "variables": Array [], "visibility": 2, }, ], "name": "StaticThings", "properties": Array [ PropertyDeclaration { "end": 1584, "isOptional": false, "isStatic": true, "name": "prop", "start": 1557, "type": "string", "visibility": 2, }, ], "start": 1532, } `; exports[`TypescriptParser Declaration parsing Enums should parse an enum correctly 1`] = ` EnumDeclaration { "end": 58, "isExported": false, "members": Array [ "Member1", "Member2", "Member3", ], "name": "Enumeration", "start": 0, } `; exports[`TypescriptParser Declaration parsing Enums should parse an exported enum correctly 1`] = ` EnumDeclaration { "end": 136, "isExported": true, "members": Array [ "ConstMember1", "ConstMember2", ], "name": "ConstantEnumeration", "start": 60, } `; exports[`TypescriptParser Declaration parsing Functions should parse a function correctly 1`] = ` FunctionDeclaration { "end": 84, "isAsync": false, "isExported": false, "name": "function1", "parameters": Array [ ParameterDeclaration { "end": 25, "name": "param1", "start": 19, "type": undefined, }, ], "start": 0, "type": "string", "variables": Array [ VariableDeclaration { "end": 61, "isConst": false, "isExported": false, "name": "var1", "start": 41, "type": undefined, }, ], } `; exports[`TypescriptParser Declaration parsing Functions should parse an exported function correctly 1`] = ` FunctionDeclaration { "end": 219, "isAsync": false, "isExported": true, "name": "function2", "parameters": Array [ ParameterDeclaration { "end": 126, "name": "param1", "start": 112, "type": "string", }, ObjectBoundParameterDeclaration { "end": 152, "endCharacter": "}", "parameters": Array [ ParameterDeclaration { "end": 139, "name": "objParam1", "start": 130, "type": undefined, }, ParameterDeclaration { "end": 150, "name": "objParam2", "start": 141, "type": undefined, }, ], "start": 128, "startCharacter": "{", }, ArrayBoundParameterDeclaration { "end": 176, "endCharacter": "]", "parameters": Array [ ParameterDeclaration { "end": 164, "name": "arrParam1", "start": 155, "type": undefined, }, ParameterDeclaration { "end": 175, "name": "arrParam2", "start": 166, "type": undefined, }, ], "start": 154, "startCharacter": "[", }, ], "start": 86, "type": "void", "variables": Array [ VariableDeclaration { "end": 217, "isConst": true, "isExported": false, "name": "constVar1", "start": 190, "type": undefined, }, ], } `; exports[`TypescriptParser Declaration parsing Functions should parse parameters correctly 1`] = ` Array [ ParameterDeclaration { "end": 25, "name": "param1", "start": 19, "type": undefined, }, ] `; exports[`TypescriptParser Declaration parsing Functions should parse parameters correctly 2`] = ` Array [ ParameterDeclaration { "end": 126, "name": "param1", "start": 112, "type": "string", }, ObjectBoundParameterDeclaration { "end": 152, "endCharacter": "}", "parameters": Array [ ParameterDeclaration { "end": 139, "name": "objParam1", "start": 130, "type": undefined, }, ParameterDeclaration { "end": 150, "name": "objParam2", "start": 141, "type": undefined, }, ], "start": 128, "startCharacter": "{", }, ArrayBoundParameterDeclaration { "end": 176, "endCharacter": "]", "parameters": Array [ ParameterDeclaration { "end": 164, "name": "arrParam1", "start": 155, "type": undefined, }, ParameterDeclaration { "end": 175, "name": "arrParam2", "start": 166, "type": undefined, }, ], "start": 154, "startCharacter": "[", }, ] `; exports[`TypescriptParser Declaration parsing Functions should parse variables correctly 1`] = ` Array [ VariableDeclaration { "end": 61, "isConst": false, "isExported": false, "name": "var1", "start": 41, "type": undefined, }, ] `; exports[`TypescriptParser Declaration parsing Functions should parse variables correctly 2`] = ` Array [ VariableDeclaration { "end": 217, "isConst": true, "isExported": false, "name": "constVar1", "start": 190, "type": undefined, }, ] `; exports[`TypescriptParser Declaration parsing Interfaces should parse a non exported interface 1`] = ` InterfaceDeclaration { "accessors": Array [], "end": 130, "isExported": false, "methods": Array [ MethodDeclaration { "end": 93, "isAbstract": true, "isAsync": false, "isOptional": false, "isStatic": false, "name": "method1", "parameters": Array [], "start": 83, "type": undefined, "variables": Array [], "visibility": 2, }, MethodDeclaration { "end": 128, "isAbstract": true, "isAsync": false, "isOptional": false, "isStatic": false, "name": "method2", "parameters": Array [ ParameterDeclaration { "end": 120, "name": "param1", "start": 106, "type": "string", }, ], "start": 98, "type": "void", "variables": Array [], "visibility": 2, }, ], "name": "NonExportedInterface", "properties": Array [ PropertyDeclaration { "end": 55, "isOptional": false, "isStatic": false, "name": "property1", "start": 37, "type": "string", "visibility": 2, }, PropertyDeclaration { "end": 78, "isOptional": false, "isStatic": false, "name": "property2", "start": 60, "type": "number", "visibility": 2, }, ], "start": 0, } `; exports[`TypescriptParser Declaration parsing Interfaces should parse an exported interface 1`] = ` InterfaceDeclaration { "accessors": Array [], "end": 286, "isExported": true, "methods": Array [ MethodDeclaration { "end": 247, "isAbstract": true, "isAsync": false, "isOptional": false, "isStatic": false, "name": "method1", "parameters": Array [ ObjectBoundParameterDeclaration { "end": 245, "endCharacter": "}", "parameters": Array [ ParameterDeclaration { "end": 235, "name": "param1", "start": 229, "type": undefined, }, ParameterDeclaration { "end": 243, "name": "param2", "start": 237, "type": undefined, }, ], "start": 227, "startCharacter": "{", }, ], "start": 219, "type": undefined, "variables": Array [], "visibility": 2, }, MethodDeclaration { "end": 284, "isAbstract": true, "isAsync": false, "isOptional": false, "isStatic": false, "name": "method2", "parameters": Array [ ArrayBoundParameterDeclaration { "end": 276, "endCharacter": "]", "parameters": Array [ ParameterDeclaration { "end": 267, "name": "param1", "start": 261, "type": undefined, }, ParameterDeclaration { "end": 275, "name": "param2", "start": 269, "type": undefined, }, ], "start": 260, "startCharacter": "[", }, ], "start": 252, "type": "void", "variables": Array [], "visibility": 2, }, ], "name": "ExportedInterface", "properties": Array [ PropertyDeclaration { "end": 191, "isOptional": false, "isStatic": false, "name": "property1", "start": 173, "type": "string", "visibility": 2, }, PropertyDeclaration { "end": 214, "isOptional": false, "isStatic": false, "name": "property2", "start": 196, "type": "number", "visibility": 2, }, ], "start": 132, } `; exports[`TypescriptParser Declaration parsing Interfaces should parse optional functions 1`] = ` InterfaceDeclaration { "accessors": Array [], "end": 714, "isExported": false, "methods": Array [ MethodDeclaration { "end": 680, "isAbstract": true, "isAsync": false, "isOptional": false, "isStatic": false, "name": "nonOptionalFunction2", "parameters": Array [], "start": 651, "type": "void", "variables": Array [], "visibility": 2, }, MethodDeclaration { "end": 712, "isAbstract": true, "isAsync": false, "isOptional": true, "isStatic": false, "name": "optionalFunction3", "parameters": Array [], "start": 685, "type": "void", "variables": Array [], "visibility": 2, }, ], "name": "OptionalFunctionInterface", "properties": Array [ PropertyDeclaration { "end": 572, "isOptional": false, "isStatic": false, "name": "nonOptionalFunction1", "start": 539, "type": "() => void", "visibility": 2, }, PropertyDeclaration { "end": 610, "isOptional": true, "isStatic": false, "name": "optionalFunction1", "start": 577, "type": "{ (): void }", "visibility": 2, }, PropertyDeclaration { "end": 646, "isOptional": true, "isStatic": false, "name": "optionalFunction2", "start": 615, "type": "() => void", "visibility": 2, }, ], "start": 497, } `; exports[`TypescriptParser Declaration parsing Interfaces should parse optional properties 1`] = ` Array [ PropertyDeclaration { "end": 422, "isOptional": false, "isStatic": false, "name": "nonOptional", "start": 402, "type": "string", "visibility": 2, }, PropertyDeclaration { "end": 470, "isOptional": false, "isStatic": false, "name": "alsoNonOptional", "start": 427, "type": "string | null | undefined", "visibility": 2, }, PropertyDeclaration { "end": 493, "isOptional": true, "isStatic": false, "name": "optional", "start": 475, "type": "string", "visibility": 2, }, ] `; exports[`TypescriptParser Declaration parsing Modules should parse a module 1`] = ` Module { "declarations": Array [ FunctionDeclaration { "end": 62, "isAsync": false, "isExported": true, "name": "modFunc", "parameters": Array [], "start": 30, "type": "void", "variables": Array [], }, ], "end": 64, "exports": Array [], "imports": Array [], "name": "Module", "resources": Array [], "start": 0, "usages": Array [], } `; exports[`TypescriptParser Declaration parsing Modules should parse a namespace 1`] = ` Namespace { "declarations": Array [ ClassDeclaration { "accessors": Array [], "end": 121, "isExported": false, "methods": Array [], "name": "NotExported", "properties": Array [], "start": 100, }, EnumDeclaration { "end": 188, "isExported": true, "members": Array [ "MemberA", "MemberB", ], "name": "Exported", "start": 127, }, ], "end": 190, "exports": Array [], "imports": Array [], "name": "Namespace", "resources": Array [], "start": 66, "usages": Array [ "Namespace", "MemberA", "MemberB", ], } `; exports[`TypescriptParser Declaration parsing Parameters should generate the correct name for an array 1`] = `"[ p1, p2 ]"`; exports[`TypescriptParser Declaration parsing Parameters should generate the correct name for an object 1`] = `"{ p1, p2 }"`; exports[`TypescriptParser Declaration parsing Parameters should generate the correct type for an array 1`] = `"{ string, Type }"`; exports[`TypescriptParser Declaration parsing Parameters should generate the correct type for an object 1`] = `"{ string, number }"`; exports[`TypescriptParser Declaration parsing Parameters should parse a normal parameter 1`] = ` ParameterDeclaration { "end": 26, "name": "p1", "start": 16, "type": "string", } `; exports[`TypescriptParser Declaration parsing Parameters should parse a simple array binding pattern 1`] = ` ArrayBoundParameterDeclaration { "end": 66, "endCharacter": "]", "parameters": Array [ ParameterDeclaration { "end": 61, "name": "p1", "start": 59, "type": undefined, }, ParameterDeclaration { "end": 65, "name": "p2", "start": 63, "type": undefined, }, ], "start": 58, "startCharacter": "[", } `; exports[`TypescriptParser Declaration parsing Parameters should parse a simple object binding pattern 1`] = ` ObjectBoundParameterDeclaration { "end": 281, "endCharacter": "}", "parameters": Array [ ParameterDeclaration { "end": 275, "name": "p1", "start": 273, "type": undefined, }, ParameterDeclaration { "end": 279, "name": "p2", "start": 277, "type": undefined, }, ], "start": 271, "startCharacter": "{", } `; exports[`TypescriptParser Declaration parsing Parameters should parse an array with overtyped tuple type 1`] = ` ArrayBoundParameterDeclaration { "end": 239, "endCharacter": "]", "parameters": Array [ ParameterDeclaration { "end": 207, "name": "p1", "start": 205, "type": "string", }, ParameterDeclaration { "end": 211, "name": "p2", "start": 209, "type": "number", }, ], "start": 204, "startCharacter": "[", } `; exports[`TypescriptParser Declaration parsing Parameters should parse an array with tuple type 1`] = ` ArrayBoundParameterDeclaration { "end": 122, "endCharacter": "]", "parameters": Array [ ParameterDeclaration { "end": 101, "name": "p1", "start": 99, "type": "string", }, ParameterDeclaration { "end": 105, "name": "p2", "start": 103, "type": "Type", }, ], "start": 98, "startCharacter": "[", } `; exports[`TypescriptParser Declaration parsing Parameters should parse an array with undertyped tuple type 1`] = ` ArrayBoundParameterDeclaration { "end": 172, "endCharacter": "]", "parameters": Array [ ParameterDeclaration { "end": 157, "name": "p1", "start": 155, "type": "string", }, ParameterDeclaration { "end": 161, "name": "p2", "start": 159, "type": undefined, }, ], "start": 154, "startCharacter": "[", } `; exports[`TypescriptParser Declaration parsing Parameters should parse an object with overtyped type literal 1`] = ` ObjectBoundParameterDeclaration { "end": 538, "endCharacter": "}", "parameters": Array [ ParameterDeclaration { "end": 491, "name": "p1", "start": 489, "type": "string", }, ParameterDeclaration { "end": 495, "name": "p2", "start": 493, "type": "number", }, ], "start": 487, "startCharacter": "{", } `; exports[`TypescriptParser Declaration parsing Parameters should parse an object with type literal 1`] = ` ObjectBoundParameterDeclaration { "end": 397, "endCharacter": "}", "parameters": Array [ ParameterDeclaration { "end": 365, "name": "p1", "start": 363, "type": "string", }, ParameterDeclaration { "end": 369, "name": "p2", "start": 367, "type": "Type", }, ], "start": 361, "startCharacter": "{", } `; exports[`TypescriptParser Declaration parsing Parameters should parse an object with type reference 1`] = ` ObjectBoundParameterDeclaration { "end": 329, "endCharacter": "}", "parameters": Array [ ParameterDeclaration { "end": 317, "name": "p1", "start": 315, "type": undefined, }, ParameterDeclaration { "end": 321, "name": "p2", "start": 319, "type": undefined, }, ], "start": 313, "startCharacter": "{", "typeReference": "Type", } `; exports[`TypescriptParser Declaration parsing Parameters should parse an object with undertyped type literal 1`] = ` ObjectBoundParameterDeclaration { "end": 455, "endCharacter": "}", "parameters": Array [ ParameterDeclaration { "end": 433, "name": "p1", "start": 431, "type": "string", }, ParameterDeclaration { "end": 437, "name": "p2", "start": 435, "type": undefined, }, ], "start": 429, "startCharacter": "{", } `; exports[`TypescriptParser Declaration parsing Parameters should parse some mixed parameters (all above) 1`] = ` FunctionDeclaration { "end": 654, "isAsync": false, "isExported": false, "name": "mixed", "parameters": Array [ ParameterDeclaration { "end": 576, "name": "p1", "start": 566, "type": "string", }, ObjectBoundParameterDeclaration { "end": 616, "endCharacter": "}", "parameters": Array [ ParameterDeclaration { "end": 582, "name": "p2", "start": 580, "type": "string", }, ParameterDeclaration { "end": 586, "name": "p3", "start": 584, "type": "number", }, ], "start": 578, "startCharacter": "{", }, ArrayBoundParameterDeclaration { "end": 643, "endCharacter": "]", "parameters": Array [ ParameterDeclaration { "end": 621, "name": "p4", "start": 619, "type": "Type", }, ParameterDeclaration { "end": 625, "name": "p5", "start": 623, "type": "boolean", }, ], "start": 618, "startCharacter": "[", }, ], "start": 551, "type": "void", "variables": Array [], } `; exports[`TypescriptParser Declaration parsing Type aliases should parse a type alias correctly 1`] = ` TypeAliasDeclaration { "end": 16, "isExported": false, "name": "Alias", "start": 0, } `; exports[`TypescriptParser Declaration parsing Type aliases should parse an exported type alias correctly 1`] = ` TypeAliasDeclaration { "end": 49, "isExported": true, "name": "ExportedAlias", "start": 18, } `; exports[`TypescriptParser Declaration parsing Variables should parse a non exported const 1`] = ` VariableDeclaration { "end": 59, "isConst": true, "isExported": false, "name": "NonExportedConst", "start": 31, "type": undefined, } `; exports[`TypescriptParser Declaration parsing Variables should parse a non exported variable 1`] = ` VariableDeclaration { "end": 29, "isConst": false, "isExported": false, "name": "NonExportedVariable", "start": 0, "type": undefined, } `; exports[`TypescriptParser Declaration parsing Variables should parse an exported const 1`] = ` VariableDeclaration { "end": 128, "isConst": true, "isExported": true, "name": "ExportedConst", "start": 96, "type": undefined, } `; exports[`TypescriptParser Declaration parsing Variables should parse an exported multiline variable 1`] = ` VariableDeclaration { "end": 206, "isConst": false, "isExported": true, "name": "MultiLet1", "start": 160, "type": undefined, } `; exports[`TypescriptParser Declaration parsing Variables should parse an exported multiline variable 2`] = ` VariableDeclaration { "end": 206, "isConst": false, "isExported": true, "name": "MultiLet2", "start": 160, "type": undefined, } `; exports[`TypescriptParser Declaration parsing Variables should parse an exported scope variable 1`] = ` VariableDeclaration { "end": 158, "isConst": false, "isExported": true, "name": "ExportedLet", "start": 130, "type": undefined, } `; exports[`TypescriptParser Declaration parsing Variables should parse an exported variable 1`] = ` VariableDeclaration { "end": 94, "isConst": false, "isExported": true, "name": "ExportedVariable", "start": 61, "type": undefined, } `; exports[`TypescriptParser Export parsing should parse aliased export named from another file 1`] = ` SymbolSpecifier { "alias": "Alias", "specifier": "Specifier", } `; exports[`TypescriptParser Export parsing should parse default export 1`] = ` DefaultDeclaration { "end": undefined, "isExported": true, "name": "DefaultExport", "resource": File { "declarations": Array [ [Circular], ], "end": 139, "exports": Array [ AllExport { "end": 28, "from": "./OtherFile", "start": 0, }, NamedExport { "end": 90, "from": "./AnotherFile", "specifiers": Array [ SymbolSpecifier { "alias": undefined, "specifier": "Specifier", }, SymbolSpecifier { "alias": "Alias", "specifier": "Specifier", }, ], "start": 30, }, AssignedExport { "declarationIdentifier": "Foo", "end": 105, "resource": [Circular], "start": 92, }, ], "imports": Array [], "resources": Array [], "start": 0, "usages": Array [ "Specifier", "Alias", "Foo", "DefaultExport", ], }, "start": undefined, } `; exports[`TypescriptParser Export parsing should parse export all from another file 1`] = ` AllExport { "end": 28, "from": "./OtherFile", "start": 0, } `; exports[`TypescriptParser Export parsing should parse export assignment 1`] = ` AssignedExport { "declarationIdentifier": "Foo", "end": 105, "resource": File { "declarations": Array [ DefaultDeclaration { "end": undefined, "isExported": true, "name": "DefaultExport", "resource": [Circular], "start": undefined, }, ], "end": 139, "exports": Array [ AllExport { "end": 28, "from": "./OtherFile", "start": 0, }, NamedExport { "end": 90, "from": "./AnotherFile", "specifiers": Array [ SymbolSpecifier { "alias": undefined, "specifier": "Specifier", }, SymbolSpecifier { "alias": "Alias", "specifier": "Specifier", }, ], "start": 30, }, [Circular], ], "imports": Array [], "resources": Array [], "start": 0, "usages": Array [ "Specifier", "Alias", "Foo", "DefaultExport", ], }, "start": 92, } `; exports[`TypescriptParser Export parsing should parse export named from another file 1`] = ` NamedExport { "end": 90, "from": "./AnotherFile", "specifiers": Array [ SymbolSpecifier { "alias": undefined, "specifier": "Specifier", }, SymbolSpecifier { "alias": "Alias", "specifier": "Specifier", }, ], "start": 30, } `; exports[`TypescriptParser Import parsing should not parse a wrong default statement 1`] = ` File { "declarations": Array [], "end": 32, "exports": Array [], "filePath": "inline.tsx", "imports": Array [ NamedImport { "end": 32, "libraryName": "myLib", "specifiers": Array [ SymbolSpecifier { "alias": undefined, "specifier": "default", }, ], "start": 0, }, ], "resources": Array [], "rootPath": "/", "start": 0, "usages": Array [], } `; exports[`TypescriptParser Import parsing should parse a default import 1`] = ` NamedImport { "defaultAlias": "Foobar", "end": 332, "libraryName": "aFile", "specifiers": Array [], "start": 305, } `; exports[`TypescriptParser Import parsing should parse a mixed default / named import 1`] = ` NamedImport { "defaultAlias": "DefaultAlias", "end": 455, "libraryName": "namedImport", "specifiers": Array [ SymbolSpecifier { "alias": undefined, "specifier": "Specifier1", }, ], "start": 400, } `; exports[`TypescriptParser Import parsing should parse a multiline import 1`] = ` NamedImport { "end": 304, "libraryName": "multiLineImport", "specifiers": Array [ SymbolSpecifier { "alias": undefined, "specifier": "Spec1", }, SymbolSpecifier { "alias": "Alias2", "specifier": "Spec2", }, ], "start": 239, } `; exports[`TypescriptParser Import parsing should parse a named import with a default statement 1`] = ` NamedImport { "defaultAlias": "DefaultAlias", "end": 399, "libraryName": "namedImport", "specifiers": Array [ SymbolSpecifier { "alias": undefined, "specifier": "Specifier1", }, ], "start": 333, } `; exports[`TypescriptParser Import parsing should parse external module import 1`] = ` ExternalModuleImport { "alias": "external", "end": 238, "libraryName": "externalModule", "start": 194, } `; exports[`TypescriptParser Import parsing should parse imports 1`] = ` Array [ StringImport { "end": 22, "libraryName": "stringImport", "start": 0, }, NamedImport { "end": 88, "libraryName": "namedImport", "specifiers": Array [ SymbolSpecifier { "alias": undefined, "specifier": "Specifier1", }, SymbolSpecifier { "alias": undefined, "specifier": "Specifier2", }, SymbolSpecifier { "alias": undefined, "specifier": "Specifier3", }, ], "start": 23, }, NamedImport { "end": 147, "libraryName": "namedAliasedImport", "specifiers": Array [ SymbolSpecifier { "alias": "Alias1", "specifier": "Specifier1", }, ], "start": 89, }, NamespaceImport { "alias": "namespaceImport", "end": 193, "libraryName": "namespace", "start": 148, }, ExternalModuleImport { "alias": "external", "end": 238, "libraryName": "externalModule", "start": 194, }, NamedImport { "end": 304, "libraryName": "multiLineImport", "specifiers": Array [ SymbolSpecifier { "alias": undefined, "specifier": "Spec1", }, SymbolSpecifier { "alias": "Alias2", "specifier": "Spec2", }, ], "start": 239, }, NamedImport { "defaultAlias": "Foobar", "end": 332, "libraryName": "aFile", "specifiers": Array [], "start": 305, }, NamedImport { "defaultAlias": "DefaultAlias", "end": 399, "libraryName": "namedImport", "specifiers": Array [ SymbolSpecifier { "alias": undefined, "specifier": "Specifier1", }, ], "start": 333, }, NamedImport { "defaultAlias": "DefaultAlias", "end": 455, "libraryName": "namedImport", "specifiers": Array [ SymbolSpecifier { "alias": undefined, "specifier": "Specifier1", }, ], "start": 400, }, NamedImport { "defaultAlias": "__DefaultAlias", "end": 540, "libraryName": "namedImport", "specifiers": Array [ SymbolSpecifier { "alias": "__Specifier1", "specifier": "Specifier1", }, ], "start": 456, }, NamedImport { "defaultAlias": "__DefaultAlias", "end": 614, "libraryName": "namedImport", "specifiers": Array [ SymbolSpecifier { "alias": "__Specifier1", "specifier": "Specifier1", }, ], "start": 541, }, NamespaceImport { "alias": "__namespaceImport", "end": 662, "libraryName": "namespace", "start": 615, }, ] `; exports[`TypescriptParser Import parsing should parse named import 1`] = ` NamedImport { "end": 88, "libraryName": "namedImport", "specifiers": Array [ SymbolSpecifier { "alias": undefined, "specifier": "Specifier1", }, SymbolSpecifier { "alias": undefined, "specifier": "Specifier2", }, SymbolSpecifier { "alias": undefined, "specifier": "Specifier3", }, ], "start": 23, } `; exports[`TypescriptParser Import parsing should parse named import with aliased specifier 1`] = ` NamedImport { "end": 147, "libraryName": "namedAliasedImport", "specifiers": Array [ SymbolSpecifier { "alias": "Alias1", "specifier": "Specifier1", }, ], "start": 89, } `; exports[`TypescriptParser Import parsing should parse namespace import 1`] = ` NamespaceImport { "alias": "namespaceImport", "end": 193, "libraryName": "namespace", "start": 148, } `; exports[`TypescriptParser Import parsing should parse string import 1`] = ` StringImport { "end": 22, "libraryName": "stringImport", "start": 0, } `; exports[`TypescriptParser JSX parsing should parse a simple javascript react file correctly with "parseFile" 1`] = ` File { "declarations": Array [ ClassDeclaration { "accessors": Array [], "end": 306, "isExported": true, "methods": Array [ MethodDeclaration { "end": 304, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "render", "parameters": Array [], "start": 80, "type": undefined, "variables": Array [], "visibility": undefined, }, ], "name": "ES6Class", "properties": Array [], "start": 52, }, DefaultDeclaration { "end": undefined, "isExported": true, "name": "ES6Class", "resource": [Circular], "start": undefined, }, ], "end": 333, "exports": Array [], "imports": Array [ NamedImport { "defaultAlias": "React", "end": 26, "libraryName": "react", "specifiers": Array [], "start": 0, }, NamedImport { "defaultAlias": "$", "end": 50, "libraryName": "jquery", "specifiers": Array [], "start": 27, }, ], "resources": Array [], "start": 0, "usages": Array [ "div", "Foobar", "AnotherBar", "blub", "p", "sortFunc", "ES6Class", ], } `; exports[`TypescriptParser JSX parsing should parse a simple javascript react file correctly with "parseFiles" 1`] = ` Array [ File { "declarations": Array [ ClassDeclaration { "accessors": Array [], "end": 306, "isExported": true, "methods": Array [ MethodDeclaration { "end": 304, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "render", "parameters": Array [], "start": 80, "type": undefined, "variables": Array [], "visibility": undefined, }, ], "name": "ES6Class", "properties": Array [], "start": 52, }, DefaultDeclaration { "end": undefined, "isExported": true, "name": "ES6Class", "resource": [Circular], "start": undefined, }, ], "end": 333, "exports": Array [], "imports": Array [ NamedImport { "defaultAlias": "React", "end": 26, "libraryName": "react", "specifiers": Array [], "start": 0, }, NamedImport { "defaultAlias": "$", "end": 50, "libraryName": "jquery", "specifiers": Array [], "start": 27, }, ], "resources": Array [], "start": 0, "usages": Array [ "div", "Foobar", "AnotherBar", "blub", "p", "sortFunc", "ES6Class", ], }, ] `; exports[`TypescriptParser JSX parsing should parse a simple javascript react file correctly with "parseSource" 1`] = ` File { "declarations": Array [ ClassDeclaration { "accessors": Array [], "end": 306, "isExported": true, "methods": Array [ MethodDeclaration { "end": 304, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "render", "parameters": Array [], "start": 80, "type": undefined, "variables": Array [], "visibility": undefined, }, ], "name": "ES6Class", "properties": Array [], "start": 52, }, DefaultDeclaration { "end": undefined, "isExported": true, "name": "ES6Class", "resource": [Circular], "start": undefined, }, ], "end": 333, "exports": Array [], "filePath": "inline.tsx", "imports": Array [ NamedImport { "defaultAlias": "React", "end": 26, "libraryName": "react", "specifiers": Array [], "start": 0, }, NamedImport { "defaultAlias": "$", "end": 50, "libraryName": "jquery", "specifiers": Array [], "start": 27, }, ], "resources": Array [], "rootPath": "/", "start": 0, "usages": Array [ "div", "Foobar", "AnotherBar", "blub", "p", "sortFunc", "ES6Class", ], } `; exports[`TypescriptParser JavaScript parsing should parse a simple javascript file correctly with "parseFile" 1`] = ` File { "declarations": Array [ ClassDeclaration { "accessors": Array [], "ctor": ConstructorDeclaration { "end": 70, "name": "ES6Class", "parameters": Array [], "start": 53, "variables": Array [], }, "end": 95, "isExported": true, "methods": Array [ MethodDeclaration { "end": 93, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "doSomething", "parameters": Array [], "start": 76, "type": undefined, "variables": Array [], "visibility": undefined, }, ], "name": "ES6Class", "properties": Array [], "start": 25, }, DefaultDeclaration { "end": undefined, "isExported": true, "name": "ES6Class", "resource": [Circular], "start": undefined, }, ], "end": 122, "exports": Array [], "imports": Array [ NamedImport { "defaultAlias": "$", "end": 23, "libraryName": "jquery", "specifiers": Array [], "start": 0, }, ], "resources": Array [], "start": 0, "usages": Array [ "ES6Class", ], } `; exports[`TypescriptParser JavaScript parsing should parse a simple javascript file correctly with "parseFiles" 1`] = ` Array [ File { "declarations": Array [ ClassDeclaration { "accessors": Array [], "ctor": ConstructorDeclaration { "end": 70, "name": "ES6Class", "parameters": Array [], "start": 53, "variables": Array [], }, "end": 95, "isExported": true, "methods": Array [ MethodDeclaration { "end": 93, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "doSomething", "parameters": Array [], "start": 76, "type": undefined, "variables": Array [], "visibility": undefined, }, ], "name": "ES6Class", "properties": Array [], "start": 25, }, DefaultDeclaration { "end": undefined, "isExported": true, "name": "ES6Class", "resource": [Circular], "start": undefined, }, ], "end": 122, "exports": Array [], "imports": Array [ NamedImport { "defaultAlias": "$", "end": 23, "libraryName": "jquery", "specifiers": Array [], "start": 0, }, ], "resources": Array [], "start": 0, "usages": Array [ "ES6Class", ], }, ] `; exports[`TypescriptParser JavaScript parsing should parse a simple javascript file correctly with "parseSource" 1`] = ` File { "declarations": Array [ ClassDeclaration { "accessors": Array [], "ctor": ConstructorDeclaration { "end": 70, "name": "ES6Class", "parameters": Array [], "start": 53, "variables": Array [], }, "end": 95, "isExported": true, "methods": Array [ MethodDeclaration { "end": 93, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "doSomething", "parameters": Array [], "start": 76, "type": undefined, "variables": Array [], "visibility": undefined, }, ], "name": "ES6Class", "properties": Array [], "start": 25, }, DefaultDeclaration { "end": undefined, "isExported": true, "name": "ES6Class", "resource": [Circular], "start": undefined, }, ], "end": 122, "exports": Array [], "filePath": "inline.tsx", "imports": Array [ NamedImport { "defaultAlias": "$", "end": 23, "libraryName": "jquery", "specifiers": Array [], "start": 0, }, ], "resources": Array [], "rootPath": "/", "start": 0, "usages": Array [ "ES6Class", ], } `; exports[`TypescriptParser Source parsing should parse a source code string correctly 1`] = ` File { "declarations": Array [ ClassDeclaration { "accessors": Array [], "end": 40, "isExported": false, "methods": Array [], "name": "Foobar", "properties": Array [], "start": 25, }, VariableDeclaration { "end": 67, "isConst": true, "isExported": false, "name": "bar", "start": 42, "type": undefined, }, ], "end": 67, "exports": Array [], "filePath": "inline.tsx", "imports": Array [ NamedImport { "end": 24, "libraryName": "bar", "specifiers": Array [ SymbolSpecifier { "alias": undefined, "specifier": "foo", }, ], "start": 0, }, ], "resources": Array [], "rootPath": "/", "start": 0, "usages": Array [ "bar", "Foobar", ], } `; exports[`TypescriptParser Specific sources should parse generics in functions in classes correctly 1`] = ` File { "declarations": Array [ ClassDeclaration { "accessors": Array [], "end": 160, "isExported": true, "methods": Array [ MethodDeclaration { "end": 142, "isAbstract": false, "isAsync": false, "isOptional": false, "isStatic": false, "name": "test", "parameters": Array [], "start": 45, "type": undefined, "variables": Array [ VariableDeclaration { "end": 120, "isConst": false, "isExported": false, "name": "a", "start": 85, "type": undefined, }, VariableDeclaration { "end": 117, "isConst": false, "isExported": false, "name": "b", "start": 104, "type": undefined, }, ], "visibility": 2, }, ], "name": "TestClass", "properties": Array [], "start": 0, }, ], "end": 160, "exports": Array [], "filePath": "inline.tsx", "imports": Array [], "resources": Array [], "rootPath": "/", "start": 0, "usages": Array [ "a", "T", "b", ], } `; exports[`TypescriptParser TSX Usage parsing should parseSource correctly 1`] = ` Array [ "myComponent", "div", "complexComp", "SingleComp", "myFunc", "MyFunc", "foobarVariable", "AnotherComp", "key", "val", "valFunc", ] `; exports[`TypescriptParser TSX: Specific cases should parse the correct usages with "parseFile" 1`] = ` Array [ "containerStyle", "overflowX", "overflowY", "width", "height", "padding", "monsters", "id", "Monster", "encounters", "Encounter", "characters", "PlayerCharacter", "alignments", "sources", "selectedCampaign", "Campaign", "selectedEncounter", "loadMonsters", "loadEncounters", "saveEncounter", "encounter", "loadEncounter", "deleteEncounter", "encounterArchivedChanged", "archived", "unsavedEdits", "manualCharacters", "level", "count", "playerCharacters", "monster", "showMonster", "saveNewEncounter", "openLoad", "state", "AppState", "ownProps", "Props", "Partial", "Object", "c", "undefined", "dispatch", "Dispatch", "e", "a", "changeEncounterArchived", "manualCharCount", "MenuItem", "value", "key", "primaryText", "manualCharLevel", "playerCount", "monsterCount", "props", "EncounterPlanner", "next", "m", "JSX", "Element", "xp", "sum", "cur", "challengeRatingExperience", "adjusted", "thresholds", "easy", "medium", "hard", "deadly", "encounterDifficulty", "startCase", "k", "div", "Toolbar", "className", "ToolbarGroup", "firstChild", "RaisedButton", "label", "onClick", "primary", "lastChild", "disabled", "secondary", "SaveModal", "title", "text", "onClose", "result", "open", "Row", "Col", "xs", "style", "marginBottom", "h6", "b", "p", "margin", "textAlign", "Divider", "List", "sortBy", "char", "ListItem", "leftCheckbox", "Checkbox", "checked", "cloneDeep", "found", "SelectField", "fullWidth", "autoWidth", "floatingLabelText", "onChange", "event", "index", "parseInt", "IconButton", "marginTop", "ActionDelete", "FlatButton", "fontWeight", "fontSize", "TextField", "type", "min", "step", "tooltip", "tooltipPosition", "ActionSearch", "MonstersOverview", "onMonsterSelected", "showAdd", "encounterPlanner", "Drawer", "openSecondary", "NavigationClose", "MonsterCard", "docked", "onRequestChange", "h5", "marginLeft", "ContentArchive", "ContentUnarchive", "difficulty", "amount", "experienceThresholds", "multiplier", "name", "React", "State", "defaultState", "1", "connect", "mapStateToProps", "mapDispatchToProps", "StatelessComponent", ] `; exports[`TypescriptParser TSX: Specific cases should parse the correct usages with "parseFile" 2`] = ` Array [ "props", "Props", "EncounterPlanner", "next", "monsters", "m", "count", "monster", "encounter", "Encounter", "JSX", "Element", "xp", "sum", "cur", "challengeRatingExperience", "adjusted", "thresholds", "easy", "medium", "hard", "deadly", "encounterDifficulty", "startCase", "Object", "k", "div", "Toolbar", "className", "ToolbarGroup", "firstChild", "RaisedButton", "label", "onClick", "primary", "lastChild", "disabled", "secondary", "openLoad", "SaveModal", "title", "text", "onClose", "result", "saveNewEncounter", "open", "Row", "Col", "xs", "style", "containerStyle", "marginBottom", "h6", "b", "p", "margin", "textAlign", "Divider", "List", "sortBy", "c", "char", "key", "ListItem", "primaryText", "leftCheckbox", "Checkbox", "checked", "playerCharacters", "cloneDeep", "found", "SelectField", "fullWidth", "autoWidth", "floatingLabelText", "value", "onChange", "event", "index", "manualCharacters", "parseInt", "manualCharCount", "unsavedEdits", "manualCharLevel", "IconButton", "marginTop", "ActionDelete", "FlatButton", "level", "fontWeight", "fontSize", "TextField", "type", "min", "step", "e", "tooltip", "tooltipPosition", "showMonster", "ActionSearch", "MonstersOverview", "id", "onMonsterSelected", "showAdd", "encounterPlanner", "Drawer", "width", "openSecondary", "NavigationClose", "MonsterCard", "Monster", "docked", "onRequestChange", "h5", "marginLeft", "ContentArchive", "ContentUnarchive", "difficulty", "amount", "experienceThresholds", "monsterCount", "playerCount", "multiplier", "name", "React", "State", "defaultState", ] `; exports[`TypescriptParser TSX: Specific cases should parse the correct usages with "parseFile" 3`] = ` Array [ "JSX", "Element", "chars", "sortBy", "Object", "key", "c", "alive", "dead", "Row", "Col", "xs", "h4", "Table", "onRowSelection", "idx", "TableHeader", "displaySelectAll", "adjustForCheckbox", "TableRow", "TableHeaderColumn", "TableBody", "displayRowCheckbox", "showRowHover", "char", "style", "cursor", "TableRowColumn", "span", "title", "colSpan", "textAlign", "IconButton", "onClick", "ImageEdit", "FloatingActionButton", "position", "bottom", "right", "mini", "ContentAdd", "PlayerCharacter", "React", "Props", "State", ] `; exports[`TypescriptParser TSX: Specific cases should parse the correct usages with "parseFiles" 1`] = ` Array [ "containerStyle", "overflowX", "overflowY", "width", "height", "padding", "monsters", "id", "Monster", "encounters", "Encounter", "characters", "PlayerCharacter", "alignments", "sources", "selectedCampaign", "Campaign", "selectedEncounter", "loadMonsters", "loadEncounters", "saveEncounter", "encounter", "loadEncounter", "deleteEncounter", "encounterArchivedChanged", "archived", "unsavedEdits", "manualCharacters", "level", "count", "playerCharacters", "monster", "showMonster", "saveNewEncounter", "openLoad", "state", "AppState", "ownProps", "Props", "Partial", "Object", "c", "undefined", "dispatch", "Dispatch", "e", "a", "changeEncounterArchived", "manualCharCount", "MenuItem", "value", "key", "primaryText", "manualCharLevel", "playerCount", "monsterCount", "props", "EncounterPlanner", "next", "m", "JSX", "Element", "xp", "sum", "cur", "challengeRatingExperience", "adjusted", "thresholds", "easy", "medium", "hard", "deadly", "encounterDifficulty", "startCase", "k", "div", "Toolbar", "className", "ToolbarGroup", "firstChild", "RaisedButton", "label", "onClick", "primary", "lastChild", "disabled", "secondary", "SaveModal", "title", "text", "onClose", "result", "open", "Row", "Col", "xs", "style", "marginBottom", "h6", "b", "p", "margin", "textAlign", "Divider", "List", "sortBy", "char", "ListItem", "leftCheckbox", "Checkbox", "checked", "cloneDeep", "found", "SelectField", "fullWidth", "autoWidth", "floatingLabelText", "onChange", "event", "index", "parseInt", "IconButton", "marginTop", "ActionDelete", "FlatButton", "fontWeight", "fontSize", "TextField", "type", "min", "step", "tooltip", "tooltipPosition", "ActionSearch", "MonstersOverview", "onMonsterSelected", "showAdd", "encounterPlanner", "Drawer", "openSecondary", "NavigationClose", "MonsterCard", "docked", "onRequestChange", "h5", "marginLeft", "ContentArchive", "ContentUnarchive", "difficulty", "amount", "experienceThresholds", "multiplier", "name", "React", "State", "defaultState", "1", "connect", "mapStateToProps", "mapDispatchToProps", "StatelessComponent", ] `; exports[`TypescriptParser TSX: Specific cases should parse the correct usages with "parseFiles" 2`] = ` Array [ "props", "Props", "EncounterPlanner", "next", "monsters", "m", "count", "monster", "encounter", "Encounter", "JSX", "Element", "xp", "sum", "cur", "challengeRatingExperience", "adjusted", "thresholds", "easy", "medium", "hard", "deadly", "encounterDifficulty", "startCase", "Object", "k", "div", "Toolbar", "className", "ToolbarGroup", "firstChild", "RaisedButton", "label", "onClick", "primary", "lastChild", "disabled", "secondary", "openLoad", "SaveModal", "title", "text", "onClose", "result", "saveNewEncounter", "open", "Row", "Col", "xs", "style", "containerStyle", "marginBottom", "h6", "b", "p", "margin", "textAlign", "Divider", "List", "sortBy", "c", "char", "key", "ListItem", "primaryText", "leftCheckbox", "Checkbox", "checked", "playerCharacters", "cloneDeep", "found", "SelectField", "fullWidth", "autoWidth", "floatingLabelText", "value", "onChange", "event", "index", "manualCharacters", "parseInt", "manualCharCount", "unsavedEdits", "manualCharLevel", "IconButton", "marginTop", "ActionDelete", "FlatButton", "level", "fontWeight", "fontSize", "TextField", "type", "min", "step", "e", "tooltip", "tooltipPosition", "showMonster", "ActionSearch", "MonstersOverview", "id", "onMonsterSelected", "showAdd", "encounterPlanner", "Drawer", "width", "openSecondary", "NavigationClose", "MonsterCard", "Monster", "docked", "onRequestChange", "h5", "marginLeft", "ContentArchive", "ContentUnarchive", "difficulty", "amount", "experienceThresholds", "monsterCount", "playerCount", "multiplier", "name", "React", "State", "defaultState", ] `; exports[`TypescriptParser TSX: Specific cases should parse the correct usages with "parseFiles" 3`] = ` Array [ "JSX", "Element", "chars", "sortBy", "Object", "key", "c", "alive", "dead", "Row", "Col", "xs", "h4", "Table", "onRowSelection", "idx", "TableHeader", "displaySelectAll", "adjustForCheckbox", "TableRow", "TableHeaderColumn", "TableBody", "displayRowCheckbox", "showRowHover", "char", "style", "cursor", "TableRowColumn", "span", "title", "colSpan", "textAlign", "IconButton", "onClick", "ImageEdit", "FloatingActionButton", "position", "bottom", "right", "mini", "ContentAdd", "PlayerCharacter", "React", "Props", "State", ] `; exports[`TypescriptParser TSX: Specific cases should parse the correct usages with "parseSource" 1`] = ` Array [ "containerStyle", "overflowX", "overflowY", "width", "height", "padding", "monsters", "id", "Monster", "encounters", "Encounter", "characters", "PlayerCharacter", "alignments", "sources", "selectedCampaign", "Campaign", "selectedEncounter", "loadMonsters", "loadEncounters", "saveEncounter", "encounter", "loadEncounter", "deleteEncounter", "encounterArchivedChanged", "archived", "unsavedEdits", "manualCharacters", "level", "count", "playerCharacters", "monster", "showMonster", "saveNewEncounter", "openLoad", "state", "AppState", "ownProps", "Props", "Partial", "Object", "c", "undefined", "dispatch", "Dispatch", "e", "a", "changeEncounterArchived", "manualCharCount", "MenuItem", "value", "key", "primaryText", "manualCharLevel", "playerCount", "monsterCount", "props", "EncounterPlanner", "next", "m", "JSX", "Element", "xp", "sum", "cur", "challengeRatingExperience", "adjusted", "thresholds", "easy", "medium", "hard", "deadly", "encounterDifficulty", "startCase", "k", "div", "Toolbar", "className", "ToolbarGroup", "firstChild", "RaisedButton", "label", "onClick", "primary", "lastChild", "disabled", "secondary", "SaveModal", "title", "text", "onClose", "result", "open", "Row", "Col", "xs", "style", "marginBottom", "h6", "b", "p", "margin", "textAlign", "Divider", "List", "sortBy", "char", "ListItem", "leftCheckbox", "Checkbox", "checked", "cloneDeep", "found", "SelectField", "fullWidth", "autoWidth", "floatingLabelText", "onChange", "event", "index", "parseInt", "IconButton", "marginTop", "ActionDelete", "FlatButton", "fontWeight", "fontSize", "TextField", "type", "min", "step", "tooltip", "tooltipPosition", "ActionSearch", "MonstersOverview", "onMonsterSelected", "showAdd", "encounterPlanner", "Drawer", "openSecondary", "NavigationClose", "MonsterCard", "docked", "onRequestChange", "h5", "marginLeft", "ContentArchive", "ContentUnarchive", "difficulty", "amount", "experienceThresholds", "multiplier", "name", "React", "State", "defaultState", "inline", "connect", "mapStateToProps", "mapDispatchToProps", "StatelessComponent", ] `; exports[`TypescriptParser TSX: Specific cases should parse the correct usages with "parseSource" 2`] = ` Array [ "props", "Props", "EncounterPlanner", "next", "monsters", "m", "count", "monster", "encounter", "Encounter", "JSX", "Element", "xp", "sum", "cur", "challengeRatingExperience", "adjusted", "thresholds", "easy", "medium", "hard", "deadly", "encounterDifficulty", "startCase", "Object", "k", "div", "Toolbar", "className", "ToolbarGroup", "firstChild", "RaisedButton", "label", "onClick", "primary", "lastChild", "disabled", "secondary", "openLoad", "SaveModal", "title", "text", "onClose", "result", "saveNewEncounter", "open", "Row", "Col", "xs", "style", "containerStyle", "marginBottom", "h6", "b", "p", "margin", "textAlign", "Divider", "List", "sortBy", "c", "char", "key", "ListItem", "primaryText", "leftCheckbox", "Checkbox", "checked", "playerCharacters", "cloneDeep", "found", "SelectField", "fullWidth", "autoWidth", "floatingLabelText", "value", "onChange", "event", "index", "manualCharacters", "parseInt", "manualCharCount", "unsavedEdits", "manualCharLevel", "IconButton", "marginTop", "ActionDelete", "FlatButton", "level", "fontWeight", "fontSize", "TextField", "type", "min", "step", "e", "tooltip", "tooltipPosition", "showMonster", "ActionSearch", "MonstersOverview", "id", "onMonsterSelected", "showAdd", "encounterPlanner", "Drawer", "width", "openSecondary", "NavigationClose", "MonsterCard", "Monster", "docked", "onRequestChange", "h5", "marginLeft", "ContentArchive", "ContentUnarchive", "difficulty", "amount", "experienceThresholds", "monsterCount", "playerCount", "multiplier", "name", "React", "State", "defaultState", ] `; exports[`TypescriptParser TSX: Specific cases should parse the correct usages with "parseSource" 3`] = ` Array [ "JSX", "Element", "chars", "sortBy", "Object", "key", "c", "alive", "dead", "Row", "Col", "xs", "h4", "Table", "onRowSelection", "idx", "TableHeader", "displaySelectAll", "adjustForCheckbox", "TableRow", "TableHeaderColumn", "TableBody", "displayRowCheckbox", "showRowHover", "char", "style", "cursor", "TableRowColumn", "span", "title", "colSpan", "textAlign", "IconButton", "onClick", "ImageEdit", "FloatingActionButton", "position", "bottom", "right", "mini", "ContentAdd", "PlayerCharacter", "React", "Props", "State", ] `; ================================================ FILE: test/_workspace/.gitignore ================================================ !node_modules/ ================================================ FILE: test/_workspace/declaration-index/_index.ts ================================================ export let _index; ================================================ FILE: test/_workspace/declaration-index/another-classes.ts ================================================ export class Class1 { } ================================================ FILE: test/_workspace/declaration-index/circular-export/circularExport1.ts ================================================ export class ExportedCircularClass1 { } export * from './circularExport2'; ================================================ FILE: test/_workspace/declaration-index/circular-export/circularExport2.ts ================================================ export class ExportedCircularClass2 { } export * from './circularExport1'; ================================================ FILE: test/_workspace/declaration-index/classes.ts ================================================ export class MyClass { public doSomething(): void { } } export class FancierLibraryClass { public doSomethingAwesome(): void { } } export class Class1 { } export class Class2 { } export class Class3 { } export class Class4 { } export class Class5 { } export class Class6 { } export class Class7 { } export class Class8 { } export class Class9 { } ================================================ FILE: test/_workspace/declaration-index/exports/classes.ts ================================================ export class Class1 { } export class Class2 { } export class Class3 { } export class Class4 { } export class Class5 { } export class Class6 { } export class Class7 { } export class Class8 { } export class Class9 { } ================================================ FILE: test/_workspace/declaration-index/exports/export-alias.ts ================================================ export { Class1 as Foo, Class5 as Bar } from './classes'; ================================================ FILE: test/_workspace/declaration-index/exports/export-all.ts ================================================ export * from './classes'; ================================================ FILE: test/_workspace/declaration-index/exports/export-from-export.ts ================================================ export * from './export-some'; ================================================ FILE: test/_workspace/declaration-index/exports/export-some.ts ================================================ export { Class1, Class5 } from './classes'; ================================================ FILE: test/_workspace/declaration-index/helper-functions.ts ================================================ export function isString(str: any): str is string { return str.constructor === String; } export function isNumber(str: any): str is number { return str.constructor === Number; } ================================================ FILE: test/_workspace/declaration-index/index.ts ================================================ export let barrelExport; ================================================ FILE: test/_workspace/declaration-index/myReactTemplate.tsx ================================================ import * as React from "react"; export const myComponent = (test: string) => { return
Hello World: {test}
; } ================================================ FILE: test/_workspace/declaration-index/prototype-funcs.ts ================================================ export function toString(): string { return ''; } export function hasOwnProperty(): boolean { return false; } ================================================ FILE: test/_workspace/declaration-index/reactFile.tsx ================================================ import { myComponent } from './myReactTemplate'; export default function foobar() { return ( ); } ================================================ FILE: test/_workspace/declaration-index/specific-cases/reindex-with-global-module-export/classes.ts ================================================ export class MyClass { public doSomething(): void { } } ================================================ FILE: test/_workspace/specific-usage-cases/i18next-destructure/destructure-my-component.tsx ================================================ import * as React from 'react'; import { t } from 'i18next'; export const MyComponent = () => (

{t('foo')}

); ================================================ FILE: test/_workspace/specific-usage-cases/i18next-destructure/import-my-component.tsx ================================================ import * as i18next from 'i18next'; import * as React from 'react'; export const MyComponent = () =>

{i18next.t('foo')}

; ================================================ FILE: test/_workspace/specific-usage-cases/reexport/reexport-default.ts ================================================ import Test from './Test'; export default Test; ================================================ FILE: test/_workspace/specific-usage-cases/reexport/reexport-import.ts ================================================ import * as colors from './colors'; import * as helpers from './helpers'; import * as icons from './icons'; import * as theme from './theme'; export { colors, helpers, theme, icons }; ================================================ FILE: test/_workspace/typescript-parser/async.ts ================================================ class Class1 { public static async staticAsync() { } public func(): void { } public async asyncFunc(): Promise { } public async asyncFuncWithoutType() { } } function func(): void { } async function asyncFunc(): Promise { } async function asyncFuncWithoutType() { } function promiseFunc(): Promise { } ================================================ FILE: test/_workspace/typescript-parser/class.ts ================================================ abstract class AbstractClass { public method1() { } public abstract abstractMethod(): void; } class NonExportedClass { constructor(public param1: string) { } public method1(): void { } protected method2(): void { } private method3(): void { let variable = ''; } } export class ExportedClass { private _property: string; protected protect: string; public pub: string; public get property(): string { return this._property; } public set property(value: string) { this._property = value; } } class Generic { } class MultiGeneric { } class PropertyAccessors { public get getOnly(): string { return 'foobar'; } public set setOnly(value: any) { } public get getAndSet(): string { return ''; } public set getAndSet(value: string) { } } abstract class AbstractPropertyAccessors { public abstract get getOnly(): string; public abstract set setOnly(value: any); public abstract get getAndSet(): string; public abstract set getAndSet(value: string); } class ObjAndArrDestruct { constructor({ p1, p2 }: any, [p3, p4]: any) { } public objMethod({ p1, p2, p3 }: any): void { } public arrMethod([p1, p2, p3]: string[]): void { } public objAndArrMethod([p1, p2, p3]: string[], { p4, p5 }: any): void { } } class OptionalProperties { public nonOptional: string; public nonOptionalAsWell: string | undefined; public optional?: string; } class StaticThings { public static prop: string; public static method(): void { } public methodNonStatic(): void { } } ================================================ FILE: test/_workspace/typescript-parser/enum.ts ================================================ enum Enumeration { Member1, Member2, Member3 } export const enum ConstantEnumeration { ConstMember1, ConstMember2 } ================================================ FILE: test/_workspace/typescript-parser/exportsOnly.ts ================================================ export * from './OtherFile'; export {Specifier, Specifier as Alias} from './AnotherFile'; export = Foo; export default 'DefaultExport'; ================================================ FILE: test/_workspace/typescript-parser/function.ts ================================================ function function1(param1): string { let var1 = 'foobar'; return 'foobar'; } export function function2(param1: string, { objParam1, objParam2 }, [arrParam1, arrParam2]): void { const constVar1 = 'foobar'; } function withoutReturnType() { return ''; } function typeGuard(str: any): str is number { return str.constructor === Number; } ================================================ FILE: test/_workspace/typescript-parser/importsOnly.ts ================================================ import 'stringImport'; import { Specifier1, Specifier2, Specifier3 } from 'namedImport'; import { Specifier1 as Alias1 } from 'namedAliasedImport'; import * as namespaceImport from 'namespace'; import external = require('externalModule'); import { Spec1, Spec2 as Alias2 } from 'multiLineImport'; import Foobar from 'aFile'; import { default as DefaultAlias, Specifier1 } from 'namedImport'; import DefaultAlias, { Specifier1 } from 'namedImport'; import { default as __DefaultAlias, Specifier1 as __Specifier1 } from 'namedImport'; import __DefaultAlias, { Specifier1 as __Specifier1 } from 'namedImport'; import * as __namespaceImport from 'namespace'; ================================================ FILE: test/_workspace/typescript-parser/interface.ts ================================================ interface NonExportedInterface { property1: string; property2: number; method1(); method2(param1: string): void; } export interface ExportedInterface { property1: string; property2: number; method1({ param1, param2 }); method2([param1, param2]): void; } interface Generic { } interface MultiGeneric { } interface OptionalPropertyInterface { nonOptional: string; alsoNonOptional: string | null | undefined; optional?: string; } interface OptionalFunctionInterface { nonOptionalFunction1: () => void; optionalFunction1?: { (): void }; optionalFunction2?: () => void; nonOptionalFunction2(): void; optionalFunction3?(): void; } ================================================ FILE: test/_workspace/typescript-parser/javascript.js ================================================ import $ from 'jquery'; export class ES6Class { constructor() { } doSomething() { } } export default ES6Class; ================================================ FILE: test/_workspace/typescript-parser/jsx.jsx ================================================ import React from 'react'; import $ from 'jquery'; export class ES6Class { render() { return (

Children {sortFunc()}

); } } export default ES6Class; ================================================ FILE: test/_workspace/typescript-parser/module.ts ================================================ declare module 'Module' { export function modFunc(): void; } declare namespace Namespace { class NotExported { } export enum Exported { MemberA, MemberB } } ================================================ FILE: test/_workspace/typescript-parser/parameters.ts ================================================ function normal(p1: string): void { } function arrBound1([p1, p2]): void { } function arrBound2([p1, p2]: [string, Type]): void { } function arrBound3([p1, p2]: [string]): void { } function arrBound4([p1, p2]: [string, number, boolean]): void { } function objBound1({ p1, p2 }): void { } function objBound2({ p1, p2 }: Type): void { } function objBound3({ p1, p2 }: { p1: string, p2: Type }): void { } function objBound4({ p1, p2 }: { p1: string }): void { } function objBound5({ p1, p2 }: { p1: string, p2: number, p3: boolean }): void { } function mixed(p1: string, { p2, p3 }: { p2: string, p3: number }, [p4, p5]: [Type, boolean]): void { } ================================================ FILE: test/_workspace/typescript-parser/specific-cases/1.tsx ================================================ import Divider from 'material-ui/Divider'; import { sortBy, cloneDeep, startCase } from 'lodash'; import Checkbox from 'material-ui/Checkbox'; import Drawer from 'material-ui/Drawer'; import FlatButton from 'material-ui/FlatButton'; import IconButton from 'material-ui/IconButton'; import List from 'material-ui/List/List'; import ListItem from 'material-ui/List/ListItem'; import MenuItem from 'material-ui/MenuItem'; import RaisedButton from 'material-ui/RaisedButton'; import SelectField from 'material-ui/SelectField'; import ActionDelete from 'material-ui/svg-icons/action/delete'; import ActionSearch from 'material-ui/svg-icons/action/search'; import ContentArchive from 'material-ui/svg-icons/content/archive'; import ContentUnarchive from 'material-ui/svg-icons/content/unarchive'; import NavigationClose from 'material-ui/svg-icons/navigation/close'; import TextField from 'material-ui/TextField'; import Toolbar from 'material-ui/Toolbar/Toolbar'; import ToolbarGroup from 'material-ui/Toolbar/ToolbarGroup'; import * as React from 'react'; import { Col, Row } from 'react-flexbox-grid'; import { connect } from 'react-redux'; import { Dispatch } from 'redux'; import { changeEncounterArchived, deleteEncounter, loadEncounter, loadEncounters, saveEncounter, } from '../../actions/encounters'; import { loadMonsters } from '../../actions/monsters'; import { Campaign } from '../../models/Campaign'; import { Encounter } from '../../models/Encounter'; import { Monster } from '../../models/Monster'; import { PlayerCharacter } from '../../models/PlayerCharacter'; import { AppState } from '../../state/app.state'; import { challengeRatingExperience, experienceThresholds } from '../../utils/Variables'; import MonsterCard from '../monsters/MonsterCard'; import MonstersOverview from '../monsters/MonstersOverview'; import SaveModal from '../utilities/SaveModal'; const containerStyle = { overflowX: 'scroll', overflowY: 'visible', width: '100%', height: 'calc(100vh - 156px)', padding: '0 4px', } as any; interface Props { monsters: { [id: string]: Monster } | null; encounters: Encounter[] | null; characters: PlayerCharacter[]; alignments: string[] | null; sources: string[] | null; selectedCampaign?: Campaign; selectedEncounter?: Encounter; loadMonsters?(): void; loadEncounters?(): void; saveEncounter?(encounter: Encounter): void; loadEncounter?(encounter: Encounter): void; deleteEncounter?(encounter: Encounter): void; encounterArchivedChanged?(encounter: Encounter, archived: boolean): void; } interface State { encounter: Encounter; unsavedEdits: boolean; manualCharacters: { level: number, count: number }[]; playerCharacters: PlayerCharacter[]; monsters: { monster: Monster, count: number }[]; showMonster: Monster | null; saveNewEncounter: boolean; openLoad: boolean; } function mapStateToProps(state: AppState, ownProps: Props): Partial { return { characters: state.playerCharacters.characters ? Object.keys(state.playerCharacters.characters).map(c => state.playerCharacters.characters![c]) : [], encounters: state.encounters.encounters ? Object.keys(state.encounters.encounters).map(c => state.encounters.encounters![c]) : null, monsters: state.monsters.monsters, alignments: state.monsters.alignments, sources: state.monsters.sources, selectedCampaign: state.campaigns.selectedCampaign || undefined, selectedEncounter: state.encounters.selectedEncounter || undefined, ...ownProps, }; } function mapDispatchToProps(dispatch: Dispatch, ownProps: Props): Partial { return { loadMonsters: () => dispatch(loadMonsters()), loadEncounters: () => dispatch(loadEncounters()), saveEncounter: e => dispatch(saveEncounter(e)), loadEncounter: e => dispatch(loadEncounter(e)), deleteEncounter: e => dispatch(deleteEncounter(e)), encounterArchivedChanged: (e, a) => dispatch(changeEncounterArchived(e, a)), ...ownProps, }; } const manualCharCount = [ , , , , , , , , , , , , ]; const manualCharLevel = [ ...manualCharCount, , , , , , , , , ]; function multiplier(playerCount: number): (monsterCount: number) => number { if (playerCount < 3) { return (monsterCount: number) => { if (monsterCount <= 1) { return 1.5; } else if (monsterCount === 2) { return 2; } else if (monsterCount >= 3 && monsterCount <= 6) { return 2.5; } else if (monsterCount >= 7 && monsterCount <= 10) { return 3; } else if (monsterCount >= 11 && monsterCount <= 14) { return 4; } else { return 5; } } } else if (playerCount > 5) { return (monsterCount: number) => { if (monsterCount <= 1) { return 0.5; } else if (monsterCount === 2) { return 1; } else if (monsterCount >= 3 && monsterCount <= 6) { return 1.5; } else if (monsterCount >= 7 && monsterCount <= 10) { return 2; } else if (monsterCount >= 11 && monsterCount <= 14) { return 2.5; } else { return 3; } } } else { return (monsterCount: number) => { if (monsterCount <= 1) { return 1; } else if (monsterCount === 2) { return 1.5; } else if (monsterCount >= 3 && monsterCount <= 6) { return 2; } else if (monsterCount >= 7 && monsterCount <= 10) { return 2.5; } else if (monsterCount >= 11 && monsterCount <= 14) { return 3; } else { return 4; } } } } class EncounterPlanner extends React.Component { private static defaultState: State = { encounter: new Encounter(), unsavedEdits: false, manualCharacters: [], playerCharacters: [], monsters: [], showMonster: null, saveNewEncounter: false, openLoad: false, }; constructor(props: Props) { super(props); this.state = EncounterPlanner.defaultState; } public componentWillMount(): void { if (this.props.monsters === null) { this.props.loadMonsters!(); } if (this.props.encounters === null) { this.props.loadEncounters!(); } } public componentWillReceiveProps(next: Props): void { let monsters = this.state.monsters; if (next.selectedEncounter && this.state.encounter !== next.selectedEncounter && this.props.monsters) { monsters = next.selectedEncounter.monsters.map(m => ({ count: m.count, monster: this.props.monsters![m.id] })); } this.setState({ encounter: next.selectedEncounter || new Encounter(), monsters, }); } public render(): JSX.Element { const xp = this.state.monsters.reduce((sum, cur) => sum += cur.count * challengeRatingExperience[(cur.monster.challengeRating || 0)], 0); const adjusted = this.adjustedXp(xp); const thresholds = { easy: this.xpSumThreshold('easy'), medium: this.xpSumThreshold('medium'), hard: this.xpSumThreshold('hard'), deadly: this.xpSumThreshold('deadly'), }; const encounterDifficulty = xp <= 0 ? '' : startCase(Object.keys(thresholds).reverse().find(k => thresholds[k] <= adjusted) || 'easy'); return (
this.setState(EncounterPlanner.defaultState)} primary={true} /> this.handleSaveEncounter()} /> this.setState({ openLoad: true })} /> result ? this.saveNewEncounter(result) : this.setState({ saveNewEncounter: false })} open={this.state.saveNewEncounter} />
Difficulty
{encounterDifficulty}

Players Thresholds

Easy

{thresholds.easy}xp

Medium

{thresholds.medium}xp

Hard

{thresholds.hard}xp

Deadly

{thresholds.deadly}xp

Monsters

Total EXP

{xp}xp

Adjusted EXP

{adjusted}xp

Characters
{sortBy(this.props.characters, c => c.name.toLowerCase()).map((char, key) => ( c._id === char._id)} onClick={() => { const playerCharacters = cloneDeep(this.state.playerCharacters); const found = playerCharacters.find(c => c._id === char._id); if (found) { playerCharacters.splice(playerCharacters.indexOf(found), 1); } else { playerCharacters.push(char); } this.setState({ playerCharacters, }); }} /> } /> ))}
Manual Characters
{this.state.manualCharacters.map((char, key) => ( { const manualCharacters = cloneDeep(this.state.manualCharacters); manualCharacters[key].count = parseInt(value || '1', 10); this.setState({ manualCharacters, }); }} > {manualCharCount} { const manualCharacters = cloneDeep(this.state.manualCharacters); manualCharacters[key].level = parseInt(value || '1', 10); this.setState({ manualCharacters, unsavedEdits: true, }); }} > {manualCharLevel} { const manualCharacters = cloneDeep(this.state.manualCharacters); manualCharacters.splice(key, 1); this.setState({ manualCharacters, unsavedEdits: true, }); }} > ))} { const manualCharacters = cloneDeep(this.state.manualCharacters); manualCharacters.push({ level: 1, count: 1, }); this.setState({ manualCharacters, unsavedEdits: true, }); }} />
Monsters
{this.state.monsters.map((monster, key) => (

{monster.monster.name}

CR: {monster.monster.challengeRating || 0} XP: {challengeRatingExperience[monster.monster.challengeRating || 0]}

{ const monsters = cloneDeep(this.state.monsters); monsters[key].count = parseInt(value || '1', 10); this.setState({ monsters, unsavedEdits: true, }); }} />
this.setState({ showMonster: monster.monster })} > { const monsters = cloneDeep(this.state.monsters); monsters.splice(key, 1); this.setState({ monsters, unsavedEdits: true, }); }} >
))}
this.handleMonsterSelected(monster)} showAdd={false} encounterPlanner={true} />
this.setState({ showMonster: null })}> this.setState({ openLoad })} > this.setState({ openLoad: false })}>
Encounters
{(this.props.encounters || []).filter(e => !e.archived).map((e, key) => ( { this.props.loadEncounter!(e); this.setState({ openLoad: false }) }} > {e.name} { event.preventDefault(); event.stopPropagation(); this.props.encounterArchivedChanged!(e, !e.archived); }}> { event.preventDefault(); event.stopPropagation(); this.props.deleteEncounter!(e); }}> ))}
Archived Encounters
{(this.props.encounters || []).filter(e => e.archived).map((e, key) => ( { this.props.loadEncounter!(e); this.setState({ openLoad: false }) }} > {e.name} { event.preventDefault(); event.stopPropagation(); this.props.encounterArchivedChanged!(e, !e.archived); }}> { event.preventDefault(); event.stopPropagation(); this.props.deleteEncounter!(e); }}> ))}
); } private xpSumThreshold(difficulty: 'easy' | 'medium' | 'hard' | 'deadly'): number { let xp = 0; for (const char of this.state.manualCharacters) { const amount = experienceThresholds[char.level][difficulty]; xp += amount * char.count; } for (const char of this.state.playerCharacters) { xp += experienceThresholds[char.level || 1][difficulty]; } return xp; } private adjustedXp(xp: number): number { const monsterCount = this.state.monsters.reduce((sum, cur) => sum += cur.count, 0); const playerCount = this.state.playerCharacters.length + this.state.manualCharacters.reduce((sum, cur) => sum += cur.count, 0); return multiplier(playerCount)(monsterCount) * xp; } private handleMonsterSelected(monster: Monster): void { if (this.state.monsters.find(m => m.monster._id === monster._id)) { return; } const monsters = cloneDeep(this.state.monsters); monsters.push({ monster, count: 1 }); this.setState({ monsters, unsavedEdits: true, }); } private saveNewEncounter(name: string): void { const encounter = new Encounter(); encounter.archived = false; encounter.name = name; encounter.campaignId = this.props.selectedCampaign!._id!; encounter.monsters = this.state.monsters.map(m => ({ id: m.monster._id!, count: m.count })); this.props.saveEncounter!(encounter); this.setState({ saveNewEncounter: false, unsavedEdits: false, }); } private handleSaveEncounter(): void { if (this.state.encounter._id) { this.state.encounter.monsters = this.state.monsters.map(m => ({ id: m.monster._id!, count: m.count })); this.props.saveEncounter!(this.state.encounter); this.setState({ saveNewEncounter: false, unsavedEdits: false, }); } else { this.setState({ saveNewEncounter: true, }); } } } export default (connect(mapStateToProps, mapDispatchToProps)(EncounterPlanner) as any as React.StatelessComponent); ================================================ FILE: test/_workspace/typescript-parser/specific-cases/2.tsx ================================================ class EncounterPlanner extends React.Component { private static defaultState: State = { encounter: new Encounter(), unsavedEdits: false, manualCharacters: [], playerCharacters: [], monsters: [], showMonster: null, saveNewEncounter: false, openLoad: false, }; constructor(props: Props) { super(props); this.state = EncounterPlanner.defaultState; } public componentWillMount(): void { if (this.props.monsters === null) { this.props.loadMonsters!(); } if (this.props.encounters === null) { this.props.loadEncounters!(); } } public componentWillReceiveProps(next: Props): void { let monsters = this.state.monsters; if (next.selectedEncounter && this.state.encounter !== next.selectedEncounter && this.props.monsters) { monsters = next.selectedEncounter.monsters.map(m => ({ count: m.count, monster: this.props.monsters![m.id] })); } this.setState({ encounter: next.selectedEncounter || new Encounter(), monsters, }); } public render(): JSX.Element { const xp = this.state.monsters.reduce((sum, cur) => sum += cur.count * challengeRatingExperience[(cur.monster.challengeRating || 0)], 0); const adjusted = this.adjustedXp(xp); const thresholds = { easy: this.xpSumThreshold('easy'), medium: this.xpSumThreshold('medium'), hard: this.xpSumThreshold('hard'), deadly: this.xpSumThreshold('deadly'), }; const encounterDifficulty = xp <= 0 ? '' : startCase(Object.keys(thresholds).reverse().find(k => thresholds[k] <= adjusted) || 'easy'); return (
this.setState(EncounterPlanner.defaultState)} primary={true} /> this.handleSaveEncounter()} /> this.setState({ openLoad: true })} /> result ? this.saveNewEncounter(result) : this.setState({ saveNewEncounter: false })} open={this.state.saveNewEncounter} />
Difficulty
{encounterDifficulty}

Players Thresholds

Easy

{thresholds.easy}xp

Medium

{thresholds.medium}xp

Hard

{thresholds.hard}xp

Deadly

{thresholds.deadly}xp

Monsters

Total EXP

{xp}xp

Adjusted EXP

{adjusted}xp

Characters
{sortBy(this.props.characters, c => c.name.toLowerCase()).map((char, key) => ( c._id === char._id)} onClick={() => { const playerCharacters = cloneDeep(this.state.playerCharacters); const found = playerCharacters.find(c => c._id === char._id); if (found) { playerCharacters.splice(playerCharacters.indexOf(found), 1); } else { playerCharacters.push(char); } this.setState({ playerCharacters, }); }} /> } /> ))}
Manual Characters
{this.state.manualCharacters.map((char, key) => ( { const manualCharacters = cloneDeep(this.state.manualCharacters); manualCharacters[key].count = parseInt(value || '1', 10); this.setState({ manualCharacters, }); }} > {manualCharCount} { const manualCharacters = cloneDeep(this.state.manualCharacters); manualCharacters[key].level = parseInt(value || '1', 10); this.setState({ manualCharacters, unsavedEdits: true, }); }} > {manualCharLevel} { const manualCharacters = cloneDeep(this.state.manualCharacters); manualCharacters.splice(key, 1); this.setState({ manualCharacters, unsavedEdits: true, }); }} > ))} { const manualCharacters = cloneDeep(this.state.manualCharacters); manualCharacters.push({ level: 1, count: 1, }); this.setState({ manualCharacters, unsavedEdits: true, }); }} />
Monsters
{this.state.monsters.map((monster, key) => (

{monster.monster.name}

CR: {monster.monster.challengeRating || 0} XP: {challengeRatingExperience[monster.monster.challengeRating || 0]}

{ const monsters = cloneDeep(this.state.monsters); monsters[key].count = parseInt(value || '1', 10); this.setState({ monsters, unsavedEdits: true, }); }} />
this.setState({ showMonster: monster.monster })} > { const monsters = cloneDeep(this.state.monsters); monsters.splice(key, 1); this.setState({ monsters, unsavedEdits: true, }); }} >
))}
this.handleMonsterSelected(monster)} showAdd={false} encounterPlanner={true} />
this.setState({ showMonster: null })}> this.setState({ openLoad })} > this.setState({ openLoad: false })}>
Encounters
{(this.props.encounters || []).filter(e => !e.archived).map((e, key) => ( { this.props.loadEncounter!(e); this.setState({ openLoad: false }) }} > {e.name} { event.preventDefault(); event.stopPropagation(); this.props.encounterArchivedChanged!(e, !e.archived); }}> { event.preventDefault(); event.stopPropagation(); this.props.deleteEncounter!(e); }}> ))}
Archived Encounters
{(this.props.encounters || []).filter(e => e.archived).map((e, key) => ( { this.props.loadEncounter!(e); this.setState({ openLoad: false }) }} > {e.name} { event.preventDefault(); event.stopPropagation(); this.props.encounterArchivedChanged!(e, !e.archived); }}> { event.preventDefault(); event.stopPropagation(); this.props.deleteEncounter!(e); }}> ))}
); } private xpSumThreshold(difficulty: 'easy' | 'medium' | 'hard' | 'deadly'): number { let xp = 0; for (const char of this.state.manualCharacters) { const amount = experienceThresholds[char.level][difficulty]; xp += amount * char.count; } for (const char of this.state.playerCharacters) { xp += experienceThresholds[char.level || 1][difficulty]; } return xp; } private adjustedXp(xp: number): number { const monsterCount = this.state.monsters.reduce((sum, cur) => sum += cur.count, 0); const playerCount = this.state.playerCharacters.length + this.state.manualCharacters.reduce((sum, cur) => sum += cur.count, 0); return multiplier(playerCount)(monsterCount) * xp; } private handleMonsterSelected(monster: Monster): void { if (this.state.monsters.find(m => m.monster._id === monster._id)) { return; } const monsters = cloneDeep(this.state.monsters); monsters.push({ monster, count: 1 }); this.setState({ monsters, unsavedEdits: true, }); } private saveNewEncounter(name: string): void { const encounter = new Encounter(); encounter.archived = false; encounter.name = name; encounter.campaignId = this.props.selectedCampaign!._id!; encounter.monsters = this.state.monsters.map(m => ({ id: m.monster._id!, count: m.count })); this.props.saveEncounter!(encounter); this.setState({ saveNewEncounter: false, unsavedEdits: false, }); } private handleSaveEncounter(): void { if (this.state.encounter._id) { this.state.encounter.monsters = this.state.monsters.map(m => ({ id: m.monster._id!, count: m.count })); this.props.saveEncounter!(this.state.encounter); this.setState({ saveNewEncounter: false, unsavedEdits: false, }); } else { this.setState({ saveNewEncounter: true, }); } } } ================================================ FILE: test/_workspace/typescript-parser/specific-cases/3.tsx ================================================ class CharacterOverview extends React.Component{ public render(): JSX.Element { const chars = sortBy(this.props.characters ? Object.keys(this.props.characters).map(key => this.props.characters![key]) : [], c => (c.name || '').toLowerCase()); const alive = chars.filter(c => c.isAlive); const dead = chars.filter(c => !c.isAlive); return (

Alive Characters

this.handleRowClick(alive, idx as number)}> Name Player Level Experience {alive && alive.length ? alive.map((char, idx) => ( {char.name} {char.playerName} {char.level || 1} {char.experience || 0} )) : No alive characters found. }

Dead Characters

this.handleRowClick(dead, idx as number)}> Name Player Level Experience {dead && dead.length ? dead.map((char, idx) => ( {char.name} {char.playerName} {char.level} {char.experience} this.props.navigate!(`/characters/${char._id}`)}> )) : No dead characters found. }
this.props.navigate!('/characters/new')}>
) } private handleRowClick(chars: PlayerCharacter[], idx: number): void { const char = chars[idx]; if (char) { this.props.navigate!(`/characters/${char._id}`) } } } ================================================ FILE: test/_workspace/typescript-parser/typeAlias.ts ================================================ type Alias = {}; export type ExportedAlias = {}; ================================================ FILE: test/_workspace/typescript-parser/usagesOnly.ts ================================================ @ClassDecorator class Class { @PropertyDecorator() public notInitializedProperty; public typedProperty: TypedPropertyRef; public assignedProperty = AssignedProperty; @FunctionDecorator() public func( @ParamDecorator() param: TypedParam, defaultParam = DefaultParam) { } private prv(param): ReturnValue { let a = PropertyAccess.To.My.Foobar; functionCall(MyProperty); indexedObject[Indexing]; let b; b = AssignmentToVariable; console.log(a); console.log(b); () => () => () => NestedBinaryAssignment === true; return null; } } let a = globalFunction(); class Class extends DefaultClass { } class Class extends GenericClass { } indexedUsage[indexingUsage]; export default defaultExportUsage; ================================================ FILE: test/_workspace/typescript-parser/usagesOnly.tsx ================================================ export default function foobar() { return (
{myFunc()} {MyFunc()} {foobarVariable.map(() => ( ))}
); } ================================================ FILE: test/_workspace/typescript-parser/variable.ts ================================================ var NonExportedVariable = ''; const NonExportedConst = ''; export var ExportedVariable = ''; export const ExportedConst = ''; export let ExportedLet = ''; export let MultiLet1 = '', MultiLet2 = ''; ================================================ FILE: test/_workspace/typescript-parser/webpack-bundle.js ================================================ !function(e){function t(n){if(r[n])return r[n].exports;var a=r[n]={i:n,l:!1,exports:{}};return e[n].call(a.exports,a,a.exports,t),a.l=!0,a.exports}var n=window.webpackJsonp;window.webpackJsonp=function(r,i,o){for(var s,u,d,c=0,l=[];c0)for(n=0;n0?"future":"past"];return D(n)?n(t):n.replace(/%s/i,t)}function $(e,t){var n=e.toLowerCase();Ar[n]=Ar[n+"s"]=Ar[t]=e}function C(e){return"string"==typeof e?Ar[e]||Ar[e.toLowerCase()]:void 0}function F(e){var t,n,r={};for(n in e)c(e,n)&&(t=C(n))&&(r[t]=e[n]);return r}function W(e,t){Er[e]=t}function I(e){var t=[];for(var n in e)t.push({unit:n,priority:Er[n]});return t.sort(function(e,t){return e.priority-t.priority}),t}function R(e,n){return function(r){return null!=r?(z(this,e,r),t.updateOffset(this,n),this):N(this,e)}}function N(e,t){return e.isValid()?e._d["get"+(e._isUTC?"UTC":"")+t]():NaN}function z(e,t,n){e.isValid()&&e._d["set"+(e._isUTC?"UTC":"")+t](n)}function J(e){return e=C(e),D(this[e])?this[e]():this}function U(e,t){if("object"==typeof e){e=F(e);for(var n=I(e),r=0;r=0?n?"+":"":"-")+Math.pow(10,Math.max(0,a)).toString().substr(1)+r}function G(e,t,n,r){var a=r;"string"==typeof r&&(a=function(){return this[r]()}),e&&(Fr[e]=a),t&&(Fr[t[0]]=function(){return V(a.apply(this,arguments),t[1],t[2])}),n&&(Fr[n]=function(){return this.localeData().ordinal(a.apply(this,arguments),e)})}function q(e){return e.match(/\[[\s\S]/)?e.replace(/^\[|\]$/g,""):e.replace(/\\/g,"")}function B(e){var t,n,r=e.match(Pr);for(t=0,n=r.length;t=0&&$r.test(e);)e=e.replace($r,n),$r.lastIndex=0,r-=1;return e}function Q(e,t,n){na[e]=D(t)?t:function(e,r){return e&&n?n:t}}function X(e,t){return c(na,e)?na[e](t._strict,t._locale):new RegExp(ee(e))}function ee(e){return te(e.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(e,t,n,r,a){return t||n||r||a}))}function te(e){return e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function ne(e,t){var n,r=t;for("string"==typeof e&&(e=[e]),s(t)&&(r=function(e,n){n[t]=L(e)}),n=0;n=0&&isFinite(s.getFullYear())&&s.setFullYear(e),s}function ge(e){var t=new Date(Date.UTC.apply(null,arguments));return e<100&&e>=0&&isFinite(t.getUTCFullYear())&&t.setUTCFullYear(e),t}function Le(e,t,n){var r=7+t-n;return-(7+ge(e,0,r).getUTCDay()-t)%7+r-1}function Ye(e,t,n,r,a){var i,o,s=(7+n-r)%7,u=Le(e,r,a),d=1+7*(t-1)+s+u;return d<=0?(i=e-1,o=pe(i)+d):d>pe(e)?(i=e+1,o=d-pe(e)):(i=e,o=d),{year:i,dayOfYear:o}}function ke(e,t,n){var r,a,i=Le(e.year(),t,n),o=Math.floor((e.dayOfYear()-i-1)/7)+1;return o<1?(a=e.year()-1,r=o+be(a,t,n)):o>be(e.year(),t,n)?(r=o-be(e.year(),t,n),a=e.year()+1):(a=e.year(),r=o),{week:r,year:a}}function be(e,t,n){var r=Le(e,t,n),a=Le(e+1,t,n);return(pe(e)-r+a)/7}function we(e){return ke(e,this._week.dow,this._week.doy).week}function De(){return this._week.dow}function Te(){return this._week.doy}function Se(e){var t=this.localeData().week(this);return null==e?t:this.add(7*(e-t),"d")}function je(e){var t=ke(this,1,4).week;return null==e?t:this.add(7*(e-t),"d")}function xe(e,t){return"string"!=typeof e?e:isNaN(e)?(e=t.weekdaysParse(e),"number"==typeof e?e:null):parseInt(e,10)}function He(e,t){return"string"==typeof e?t.weekdaysParse(e)%7||7:isNaN(e)?null:e}function Oe(e,t){return e?r(this._weekdays)?this._weekdays[e.day()]:this._weekdays[this._weekdays.isFormat.test(t)?"format":"standalone"][e.day()]:r(this._weekdays)?this._weekdays:this._weekdays.standalone}function Ae(e){return e?this._weekdaysShort[e.day()]:this._weekdaysShort}function Ee(e){return e?this._weekdaysMin[e.day()]:this._weekdaysMin}function Pe(e,t,n){var r,a,i,o=e.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],r=0;r<7;++r)i=_([2e3,1]).day(r),this._minWeekdaysParse[r]=this.weekdaysMin(i,"").toLocaleLowerCase(),this._shortWeekdaysParse[r]=this.weekdaysShort(i,"").toLocaleLowerCase(),this._weekdaysParse[r]=this.weekdays(i,"").toLocaleLowerCase();return n?"dddd"===t?(a=fa.call(this._weekdaysParse,o),-1!==a?a:null):"ddd"===t?(a=fa.call(this._shortWeekdaysParse,o),-1!==a?a:null):(a=fa.call(this._minWeekdaysParse,o),-1!==a?a:null):"dddd"===t?-1!==(a=fa.call(this._weekdaysParse,o))?a:-1!==(a=fa.call(this._shortWeekdaysParse,o))?a:(a=fa.call(this._minWeekdaysParse,o),-1!==a?a:null):"ddd"===t?-1!==(a=fa.call(this._shortWeekdaysParse,o))?a:-1!==(a=fa.call(this._weekdaysParse,o))?a:(a=fa.call(this._minWeekdaysParse,o),-1!==a?a:null):-1!==(a=fa.call(this._minWeekdaysParse,o))?a:-1!==(a=fa.call(this._weekdaysParse,o))?a:(a=fa.call(this._shortWeekdaysParse,o),-1!==a?a:null)}function $e(e,t,n){var r,a,i;if(this._weekdaysParseExact)return Pe.call(this,e,t,n);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),r=0;r<7;r++){if(a=_([2e3,1]).day(r),n&&!this._fullWeekdaysParse[r]&&(this._fullWeekdaysParse[r]=new RegExp("^"+this.weekdays(a,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[r]=new RegExp("^"+this.weekdaysShort(a,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[r]=new RegExp("^"+this.weekdaysMin(a,"").replace(".",".?")+"$","i")),this._weekdaysParse[r]||(i="^"+this.weekdays(a,"")+"|^"+this.weekdaysShort(a,"")+"|^"+this.weekdaysMin(a,""),this._weekdaysParse[r]=new RegExp(i.replace(".",""),"i")),n&&"dddd"===t&&this._fullWeekdaysParse[r].test(e))return r;if(n&&"ddd"===t&&this._shortWeekdaysParse[r].test(e))return r;if(n&&"dd"===t&&this._minWeekdaysParse[r].test(e))return r;if(!n&&this._weekdaysParse[r].test(e))return r}}function Ce(e){if(!this.isValid())return null!=e?this:NaN;var t=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=e?(e=xe(e,this.localeData()),this.add(e-t,"d")):t}function Fe(e){if(!this.isValid())return null!=e?this:NaN;var t=(this.day()+7-this.localeData()._week.dow)%7;return null==e?t:this.add(e-t,"d")}function We(e){if(!this.isValid())return null!=e?this:NaN;if(null!=e){var t=He(e,this.localeData());return this.day(this.day()%7?t:t-7)}return this.day()||7}function Ie(e){return this._weekdaysParseExact?(c(this,"_weekdaysRegex")||ze.call(this),e?this._weekdaysStrictRegex:this._weekdaysRegex):(c(this,"_weekdaysRegex")||(this._weekdaysRegex=ba),this._weekdaysStrictRegex&&e?this._weekdaysStrictRegex:this._weekdaysRegex)}function Re(e){return this._weekdaysParseExact?(c(this,"_weekdaysRegex")||ze.call(this),e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(c(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=wa),this._weekdaysShortStrictRegex&&e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Ne(e){return this._weekdaysParseExact?(c(this,"_weekdaysRegex")||ze.call(this),e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(c(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=Da),this._weekdaysMinStrictRegex&&e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function ze(){function e(e,t){return t.length-e.length}var t,n,r,a,i,o=[],s=[],u=[],d=[];for(t=0;t<7;t++)n=_([2e3,1]).day(t),r=this.weekdaysMin(n,""),a=this.weekdaysShort(n,""),i=this.weekdays(n,""),o.push(r),s.push(a),u.push(i),d.push(r),d.push(a),d.push(i);for(o.sort(e),s.sort(e),u.sort(e),d.sort(e),t=0;t<7;t++)s[t]=te(s[t]),u[t]=te(u[t]),d[t]=te(d[t]);this._weekdaysRegex=new RegExp("^("+d.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+u.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+s.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+o.join("|")+")","i")}function Je(){return this.hours()%12||12}function Ue(){return this.hours()||24}function Ve(e,t){G(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)})}function Ge(e,t){return t._meridiemParse}function qe(e){return"p"===(e+"").toLowerCase().charAt(0)}function Be(e,t,n){return e>11?n?"pm":"PM":n?"am":"AM"}function Ke(e){return e?e.toLowerCase().replace("_","-"):e}function Ze(e){for(var t,n,r,a,i=0;i0;){if(r=Qe(a.slice(0,t).join("-")))return r;if(n&&n.length>=t&&Y(a,n,!0)>=t-1)break;t--}i++}return null}function Qe(t){var r=null;if(!Ha[t]&&void 0!==e&&e&&e.exports)try{r=Ta._abbr,n(597)("./"+t),Xe(r)}catch(e){}return Ha[t]}function Xe(e,t){var n;return e&&(n=o(t)?nt(e):et(e,t))&&(Ta=n),Ta._abbr}function et(e,t){if(null!==t){var n=xa;if(t.abbr=e,null!=Ha[e])w("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),n=Ha[e]._config;else if(null!=t.parentLocale){if(null==Ha[t.parentLocale])return Oa[t.parentLocale]||(Oa[t.parentLocale]=[]),Oa[t.parentLocale].push({name:e,config:t}),null;n=Ha[t.parentLocale]._config}return Ha[e]=new j(S(n,t)),Oa[e]&&Oa[e].forEach(function(e){et(e.name,e.config)}),Xe(e),Ha[e]}return delete Ha[e],null}function tt(e,t){if(null!=t){var n,r=xa;null!=Ha[e]&&(r=Ha[e]._config),t=S(r,t),n=new j(t),n.parentLocale=Ha[e],Ha[e]=n,Xe(e)}else null!=Ha[e]&&(null!=Ha[e].parentLocale?Ha[e]=Ha[e].parentLocale:null!=Ha[e]&&delete Ha[e]);return Ha[e]}function nt(e){var t;if(e&&e._locale&&e._locale._abbr&&(e=e._locale._abbr),!e)return Ta;if(!r(e)){if(t=Qe(e))return t;e=[e]}return Ze(e)}function rt(){return Sr(Ha)}function at(e){var t,n=e._a;return n&&-2===m(e).overflow&&(t=n[ia]<0||n[ia]>11?ia:n[oa]<1||n[oa]>ie(n[aa],n[ia])?oa:n[sa]<0||n[sa]>24||24===n[sa]&&(0!==n[ua]||0!==n[da]||0!==n[ca])?sa:n[ua]<0||n[ua]>59?ua:n[da]<0||n[da]>59?da:n[ca]<0||n[ca]>999?ca:-1,m(e)._overflowDayOfYear&&(toa)&&(t=oa),m(e)._overflowWeeks&&-1===t&&(t=la),m(e)._overflowWeekday&&-1===t&&(t=_a),m(e).overflow=t),e}function it(e){var t,n,r,a,i,o,s=e._i,u=Aa.exec(s)||Ea.exec(s);if(u){for(m(e).iso=!0,t=0,n=$a.length;t10?"YYYY ":"YY "),i="HH:mm"+(n[4]?":ss":""),n[1]){var l=new Date(n[2]),_=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][l.getDay()];if(n[1].substr(0,3)!==_)return m(e).weekdayMismatch=!0,void(e._isValid=!1)}switch(n[5].length){case 2:0===u?s=" +0000":(u=c.indexOf(n[5][1].toUpperCase())-12,s=(u<0?" -":" +")+(""+u).replace(/^-?/,"0").match(/..$/)[0]+"00");break;case 4:s=d[n[5]];break;default:s=d[" GMT"]}n[5]=s,e._i=n.splice(1).join(""),o=" ZZ",e._f=r+a+i+o,_t(e),m(e).rfc2822=!0}else e._isValid=!1}function st(e){var n=Fa.exec(e._i);if(null!==n)return void(e._d=new Date(+n[1]));it(e),!1===e._isValid&&(delete e._isValid,ot(e),!1===e._isValid&&(delete e._isValid,t.createFromInputFallback(e)))}function ut(e,t,n){return null!=e?e:null!=t?t:n}function dt(e){var n=new Date(t.now());return e._useUTC?[n.getUTCFullYear(),n.getUTCMonth(),n.getUTCDate()]:[n.getFullYear(),n.getMonth(),n.getDate()]}function ct(e){var t,n,r,a,i=[];if(!e._d){for(r=dt(e),e._w&&null==e._a[oa]&&null==e._a[ia]&<(e),null!=e._dayOfYear&&(a=ut(e._a[aa],r[aa]),(e._dayOfYear>pe(a)||0===e._dayOfYear)&&(m(e)._overflowDayOfYear=!0),n=ge(a,0,e._dayOfYear),e._a[ia]=n.getUTCMonth(),e._a[oa]=n.getUTCDate()),t=0;t<3&&null==e._a[t];++t)e._a[t]=i[t]=r[t];for(;t<7;t++)e._a[t]=i[t]=null==e._a[t]?2===t?1:0:e._a[t];24===e._a[sa]&&0===e._a[ua]&&0===e._a[da]&&0===e._a[ca]&&(e._nextDay=!0,e._a[sa]=0),e._d=(e._useUTC?ge:Me).apply(null,i),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[sa]=24)}}function lt(e){var t,n,r,a,i,o,s,u;if(t=e._w,null!=t.GG||null!=t.W||null!=t.E)i=1,o=4,n=ut(t.GG,e._a[aa],ke(gt(),1,4).year),r=ut(t.W,1),((a=ut(t.E,1))<1||a>7)&&(u=!0);else{i=e._locale._week.dow,o=e._locale._week.doy;var d=ke(gt(),i,o);n=ut(t.gg,e._a[aa],d.year),r=ut(t.w,d.week),null!=t.d?((a=t.d)<0||a>6)&&(u=!0):null!=t.e?(a=t.e+i,(t.e<0||t.e>6)&&(u=!0)):a=i}r<1||r>be(n,i,o)?m(e)._overflowWeeks=!0:null!=u?m(e)._overflowWeekday=!0:(s=Ye(n,r,a,i,o),e._a[aa]=s.year,e._dayOfYear=s.dayOfYear)}function _t(e){if(e._f===t.ISO_8601)return void it(e);if(e._f===t.RFC_2822)return void ot(e);e._a=[],m(e).empty=!0;var n,r,a,i,o,s=""+e._i,u=s.length,d=0;for(a=Z(e._f,e._locale).match(Pr)||[],n=0;n0&&m(e).unusedInput.push(o),s=s.slice(s.indexOf(r)+r.length),d+=r.length),Fr[i]?(r?m(e).empty=!1:m(e).unusedTokens.push(i),ae(i,r,e)):e._strict&&!r&&m(e).unusedTokens.push(i);m(e).charsLeftOver=u-d,s.length>0&&m(e).unusedInput.push(s),e._a[sa]<=12&&!0===m(e).bigHour&&e._a[sa]>0&&(m(e).bigHour=void 0),m(e).parsedDateParts=e._a.slice(0),m(e).meridiem=e._meridiem,e._a[sa]=ft(e._locale,e._a[sa],e._meridiem),ct(e),at(e)}function ft(e,t,n){var r;return null==n?t:null!=e.meridiemHour?e.meridiemHour(t,n):null!=e.isPM?(r=e.isPM(n),r&&t<12&&(t+=12),r||12!==t||(t=0),t):t}function mt(e){var t,n,r,a,i;if(0===e._f.length)return m(e).invalidFormat=!0,void(e._d=new Date(NaN));for(a=0;athis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Rt(){if(!o(this._isDSTShifted))return this._isDSTShifted;var e={};if(y(e,this),e=yt(e),e._a){var t=e._isUTC?_(e._a):gt(e._a);this._isDSTShifted=this.isValid()&&Y(e._a,t.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Nt(){return!!this.isValid()&&!this._isUTC}function zt(){return!!this.isValid()&&this._isUTC}function Jt(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function Ut(e,t){var n,r,a,i=e,o=null;return St(e)?i={ms:e._milliseconds,d:e._days,M:e._months}:s(e)?(i={},t?i[t]=e:i.milliseconds=e):(o=Ua.exec(e))?(n="-"===o[1]?-1:1,i={y:0,d:L(o[oa])*n,h:L(o[sa])*n,m:L(o[ua])*n,s:L(o[da])*n,ms:L(jt(1e3*o[ca]))*n}):(o=Va.exec(e))?(n="-"===o[1]?-1:1,i={y:Vt(o[2],n),M:Vt(o[3],n),w:Vt(o[4],n),d:Vt(o[5],n),h:Vt(o[6],n),m:Vt(o[7],n),s:Vt(o[8],n)}):null==i?i={}:"object"==typeof i&&("from"in i||"to"in i)&&(a=qt(gt(i.from),gt(i.to)),i={},i.ms=a.milliseconds,i.M=a.months),r=new Tt(i),St(e)&&c(e,"_locale")&&(r._locale=e._locale),r}function Vt(e,t){var n=e&&parseFloat(e.replace(",","."));return(isNaN(n)?0:n)*t}function Gt(e,t){var n={milliseconds:0,months:0};return n.months=t.month()-e.month()+12*(t.year()-e.year()),e.clone().add(n.months,"M").isAfter(t)&&--n.months,n.milliseconds=+t-+e.clone().add(n.months,"M"),n}function qt(e,t){var n;return e.isValid()&&t.isValid()?(t=Ot(t,e),e.isBefore(t)?n=Gt(e,t):(n=Gt(t,e),n.milliseconds=-n.milliseconds,n.months=-n.months),n):{milliseconds:0,months:0}}function Bt(e,t){return function(n,r){var a,i;return null===r||isNaN(+r)||(w(t,"moment()."+t+"(period, number) is deprecated. Please use moment()."+t+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),i=n,n=r,r=i),n="string"==typeof n?+n:n,a=Ut(n,r),Kt(this,a,e),this}}function Kt(e,n,r,a){var i=n._milliseconds,o=jt(n._days),s=jt(n._months);e.isValid()&&(a=null==a||a,i&&e._d.setTime(e._d.valueOf()+i*r),o&&z(e,"Date",N(e,"Date")+o*r),s&&ce(e,N(e,"Month")+s*r),a&&t.updateOffset(e,o||s))}function Zt(e,t){var n=e.diff(t,"days",!0);return n<-6?"sameElse":n<-1?"lastWeek":n<0?"lastDay":n<1?"sameDay":n<2?"nextDay":n<7?"nextWeek":"sameElse"}function Qt(e,n){var r=e||gt(),a=Ot(r,this).startOf("day"),i=t.calendarFormat(this,a)||"sameElse",o=n&&(D(n[i])?n[i].call(this,r):n[i]);return this.format(o||this.localeData().calendar(i,this,gt(r)))}function Xt(){return new v(this)}function en(e,t){var n=M(e)?e:gt(e);return!(!this.isValid()||!n.isValid())&&(t=C(o(t)?"millisecond":t),"millisecond"===t?this.valueOf()>n.valueOf():n.valueOf()9999?K(e,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):D(Date.prototype.toISOString)?this.toDate().toISOString():K(e,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}function ln(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var e="moment",t="";this.isLocal()||(e=0===this.utcOffset()?"moment.utc":"moment.parseZone",t="Z");var n="["+e+'("]',r=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",a=t+'[")]';return this.format(n+r+"-MM-DD[T]HH:mm:ss.SSS"+a)}function _n(e){e||(e=this.isUtc()?t.defaultFormatUtc:t.defaultFormat);var n=K(this,e);return this.localeData().postformat(n)}function fn(e,t){return this.isValid()&&(M(e)&&e.isValid()||gt(e).isValid())?Ut({to:this,from:e}).locale(this.locale()).humanize(!t):this.localeData().invalidDate()}function mn(e){return this.from(gt(),e)}function hn(e,t){return this.isValid()&&(M(e)&&e.isValid()||gt(e).isValid())?Ut({from:this,to:e}).locale(this.locale()).humanize(!t):this.localeData().invalidDate()}function pn(e){return this.to(gt(),e)}function yn(e){var t;return void 0===e?this._locale._abbr:(t=nt(e),null!=t&&(this._locale=t),this)}function vn(){return this._locale}function Mn(e){switch(e=C(e)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":case"date":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===e&&this.weekday(0),"isoWeek"===e&&this.isoWeekday(1),"quarter"===e&&this.month(3*Math.floor(this.month()/3)),this}function gn(e){return void 0===(e=C(e))||"millisecond"===e?this:("date"===e&&(e="day"),this.startOf(e).add(1,"isoWeek"===e?"week":e).subtract(1,"ms"))}function Ln(){return this._d.valueOf()-6e4*(this._offset||0)}function Yn(){return Math.floor(this.valueOf()/1e3)}function kn(){return new Date(this.valueOf())}function bn(){var e=this;return[e.year(),e.month(),e.date(),e.hour(),e.minute(),e.second(),e.millisecond()]}function wn(){var e=this;return{years:e.year(),months:e.month(),date:e.date(),hours:e.hours(),minutes:e.minutes(),seconds:e.seconds(),milliseconds:e.milliseconds()}}function Dn(){return this.isValid()?this.toISOString():null}function Tn(){return h(this)}function Sn(){return l({},m(this))}function jn(){return m(this).overflow}function xn(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function Hn(e,t){G(0,[e,e.length],0,t)}function On(e){return $n.call(this,e,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)}function An(e){return $n.call(this,e,this.isoWeek(),this.isoWeekday(),1,4)}function En(){return be(this.year(),1,4)}function Pn(){var e=this.localeData()._week;return be(this.year(),e.dow,e.doy)}function $n(e,t,n,r,a){var i;return null==e?ke(this,r,a).year:(i=be(e,r,a),t>i&&(t=i),Cn.call(this,e,t,n,r,a))}function Cn(e,t,n,r,a){var i=Ye(e,t,n,r,a),o=ge(i.year,0,i.dayOfYear);return this.year(o.getUTCFullYear()),this.month(o.getUTCMonth()),this.date(o.getUTCDate()),this}function Fn(e){return null==e?Math.ceil((this.month()+1)/3):this.month(3*(e-1)+this.month()%3)}function Wn(e){var t=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==e?t:this.add(e-t,"d")}function In(e,t){t[ca]=L(1e3*("0."+e))}function Rn(){return this._isUTC?"UTC":""}function Nn(){return this._isUTC?"Coordinated Universal Time":""}function zn(e){return gt(1e3*e)}function Jn(){return gt.apply(null,arguments).parseZone()}function Un(e){return e}function Vn(e,t,n,r){var a=nt(),i=_().set(r,t);return a[n](i,e)}function Gn(e,t,n){if(s(e)&&(t=e,e=void 0),e=e||"",null!=t)return Vn(e,t,n,"month");var r,a=[];for(r=0;r<12;r++)a[r]=Vn(e,r,n,"month");return a}function qn(e,t,n,r){"boolean"==typeof e?(s(t)&&(n=t,t=void 0),t=t||""):(t=e,n=t,e=!1,s(t)&&(n=t,t=void 0),t=t||"");var a=nt(),i=e?a._week.dow:0;if(null!=n)return Vn(t,(n+i)%7,r,"day");var o,u=[];for(o=0;o<7;o++)u[o]=Vn(t,(o+i)%7,r,"day");return u}function Bn(e,t){return Gn(e,t,"months")}function Kn(e,t){return Gn(e,t,"monthsShort")}function Zn(e,t,n){return qn(e,t,n,"weekdays")}function Qn(e,t,n){return qn(e,t,n,"weekdaysShort")}function Xn(e,t,n){return qn(e,t,n,"weekdaysMin")}function er(){var e=this._data;return this._milliseconds=ri(this._milliseconds),this._days=ri(this._days),this._months=ri(this._months),e.milliseconds=ri(e.milliseconds),e.seconds=ri(e.seconds),e.minutes=ri(e.minutes),e.hours=ri(e.hours),e.months=ri(e.months),e.years=ri(e.years),this}function tr(e,t,n,r){var a=Ut(t,n);return e._milliseconds+=r*a._milliseconds,e._days+=r*a._days,e._months+=r*a._months,e._bubble()}function nr(e,t){return tr(this,e,t,1)}function rr(e,t){return tr(this,e,t,-1)}function ar(e){return e<0?Math.floor(e):Math.ceil(e)}function ir(){var e,t,n,r,a,i=this._milliseconds,o=this._days,s=this._months,u=this._data;return i>=0&&o>=0&&s>=0||i<=0&&o<=0&&s<=0||(i+=864e5*ar(sr(s)+o),o=0,s=0),u.milliseconds=i%1e3,e=g(i/1e3),u.seconds=e%60,t=g(e/60),u.minutes=t%60,n=g(t/60),u.hours=n%24,o+=g(n/24),a=g(or(o)),s+=a,o-=ar(sr(a)),r=g(s/12),s%=12,u.days=o,u.months=s,u.years=r,this}function or(e){return 4800*e/146097}function sr(e){return 146097*e/4800}function ur(e){if(!this.isValid())return NaN;var t,n,r=this._milliseconds;if("month"===(e=C(e))||"year"===e)return t=this._days+r/864e5,n=this._months+or(t),"month"===e?n:n/12;switch(t=this._days+Math.round(sr(this._months)),e){case"week":return t/7+r/6048e5;case"day":return t+r/864e5;case"hour":return 24*t+r/36e5;case"minute":return 1440*t+r/6e4;case"second":return 86400*t+r/1e3;case"millisecond":return Math.floor(864e5*t)+r;default:throw new Error("Unknown unit "+e)}}function dr(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*L(this._months/12):NaN}function cr(e){return function(){return this.as(e)}}function lr(e){return e=C(e),this.isValid()?this[e+"s"]():NaN}function _r(e){return function(){return this.isValid()?this._data[e]:NaN}}function fr(){return g(this.days()/7)}function mr(e,t,n,r,a){return a.relativeTime(t||1,!!n,e,r)}function hr(e,t,n){var r=Ut(e).abs(),a=Mi(r.as("s")),i=Mi(r.as("m")),o=Mi(r.as("h")),s=Mi(r.as("d")),u=Mi(r.as("M")),d=Mi(r.as("y")),c=a<=gi.ss&&["s",a]||a0,c[4]=n,mr.apply(null,c)}function pr(e){return void 0===e?Mi:"function"==typeof e&&(Mi=e,!0)}function yr(e,t){return void 0!==gi[e]&&(void 0===t?gi[e]:(gi[e]=t,"s"===e&&(gi.ss=t-1),!0))}function vr(e){if(!this.isValid())return this.localeData().invalidDate();var t=this.localeData(),n=hr(this,!e,t);return e&&(n=t.pastFuture(+this,n)),t.postformat(n)}function Mr(){if(!this.isValid())return this.localeData().invalidDate();var e,t,n,r=Li(this._milliseconds)/1e3,a=Li(this._days),i=Li(this._months);e=g(r/60),t=g(e/60),r%=60,e%=60,n=g(i/12),i%=12;var o=n,s=i,u=a,d=t,c=e,l=r,_=this.asSeconds();return _?(_<0?"-":"")+"P"+(o?o+"Y":"")+(s?s+"M":"")+(u?u+"D":"")+(d||c||l?"T":"")+(d?d+"H":"")+(c?c+"M":"")+(l?l+"S":""):"P0D"}var gr,Lr;Lr=Array.prototype.some?Array.prototype.some:function(e){for(var t=Object(this),n=t.length>>>0,r=0;r68?1900:2e3)};var Ma=R("FullYear",!0);G("w",["ww",2],"wo","week"),G("W",["WW",2],"Wo","isoWeek"),$("week","w"),$("isoWeek","W"),W("week",5),W("isoWeek",5),Q("w",Jr),Q("ww",Jr,Ir),Q("W",Jr),Q("WW",Jr,Ir),re(["w","ww","W","WW"],function(e,t,n,r){t[r.substr(0,1)]=L(e)});var ga={dow:0,doy:6};G("d",0,"do","day"),G("dd",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),G("ddd",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),G("dddd",0,0,function(e){return this.localeData().weekdays(this,e)}),G("e",0,0,"weekday"),G("E",0,0,"isoWeekday"),$("day","d"),$("weekday","e"),$("isoWeekday","E"),W("day",11),W("weekday",11),W("isoWeekday",11),Q("d",Jr),Q("e",Jr),Q("E",Jr),Q("dd",function(e,t){return t.weekdaysMinRegex(e)}),Q("ddd",function(e,t){return t.weekdaysShortRegex(e)}),Q("dddd",function(e,t){return t.weekdaysRegex(e)}),re(["dd","ddd","dddd"],function(e,t,n,r){var a=n._locale.weekdaysParse(e,r,n._strict);null!=a?t.d=a:m(n).invalidWeekday=e}),re(["d","e","E"],function(e,t,n,r){t[r]=L(e)});var La="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Ya="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),ka="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),ba=ta,wa=ta,Da=ta;G("H",["HH",2],0,"hour"),G("h",["hh",2],0,Je),G("k",["kk",2],0,Ue),G("hmm",0,0,function(){return""+Je.apply(this)+V(this.minutes(),2)}),G("hmmss",0,0,function(){return""+Je.apply(this)+V(this.minutes(),2)+V(this.seconds(),2)}),G("Hmm",0,0,function(){return""+this.hours()+V(this.minutes(),2)}),G("Hmmss",0,0,function(){return""+this.hours()+V(this.minutes(),2)+V(this.seconds(),2)}),Ve("a",!0),Ve("A",!1),$("hour","h"),W("hour",13),Q("a",Ge),Q("A",Ge),Q("H",Jr),Q("h",Jr),Q("k",Jr),Q("HH",Jr,Ir),Q("hh",Jr,Ir),Q("kk",Jr,Ir),Q("hmm",Ur),Q("hmmss",Vr),Q("Hmm",Ur),Q("Hmmss",Vr),ne(["H","HH"],sa),ne(["k","kk"],function(e,t,n){var r=L(e);t[sa]=24===r?0:r}),ne(["a","A"],function(e,t,n){n._isPm=n._locale.isPM(e),n._meridiem=e}),ne(["h","hh"],function(e,t,n){t[sa]=L(e),m(n).bigHour=!0}),ne("hmm",function(e,t,n){var r=e.length-2;t[sa]=L(e.substr(0,r)),t[ua]=L(e.substr(r)),m(n).bigHour=!0}),ne("hmmss",function(e,t,n){var r=e.length-4,a=e.length-2;t[sa]=L(e.substr(0,r)),t[ua]=L(e.substr(r,2)),t[da]=L(e.substr(a)),m(n).bigHour=!0}),ne("Hmm",function(e,t,n){var r=e.length-2;t[sa]=L(e.substr(0,r)),t[ua]=L(e.substr(r))}),ne("Hmmss",function(e,t,n){var r=e.length-4,a=e.length-2;t[sa]=L(e.substr(0,r)),t[ua]=L(e.substr(r,2)),t[da]=L(e.substr(a))});var Ta,Sa=/[ap]\.?m?\.?/i,ja=R("Hours",!0),xa={calendar:jr,longDateFormat:xr,invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:Hr,relativeTime:Or,months:ha,monthsShort:pa,week:ga,weekdays:La,weekdaysMin:ka,weekdaysShort:Ya,meridiemParse:Sa},Ha={},Oa={},Aa=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Ea=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Pa=/Z|[+-]\d\d(?::?\d\d)?/,$a=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],Ca=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Fa=/^\/?Date\((\-?\d+)/i,Wa=/^((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d?\d\s(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(?:\d\d)?\d\d\s)(\d\d:\d\d)(\:\d\d)?(\s(?:UT|GMT|[ECMP][SD]T|[A-IK-Za-ik-z]|[+-]\d{4}))$/;t.createFromInputFallback=b("value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(e){e._d=new Date(e._i+(e._useUTC?" UTC":""))}),t.ISO_8601=function(){},t.RFC_2822=function(){};var Ia=b("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var e=gt.apply(null,arguments);return this.isValid()&&e.isValid()?ethis?this:e:p()}),Na=function(){return Date.now?Date.now():+new Date},za=["year","quarter","month","week","day","hour","minute","second","millisecond"];xt("Z",":"),xt("ZZ",""),Q("Z",Xr),Q("ZZ",Xr),ne(["Z","ZZ"],function(e,t,n){n._useUTC=!0,n._tzm=Ht(Xr,e)});var Ja=/([\+\-]|\d\d)/gi;t.updateOffset=function(){};var Ua=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,Va=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;Ut.fn=Tt.prototype,Ut.invalid=Dt;var Ga=Bt(1,"add"),qa=Bt(-1,"subtract");t.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",t.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var Ba=b("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(e){return void 0===e?this.localeData():this.locale(e)});G(0,["gg",2],0,function(){return this.weekYear()%100}),G(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Hn("gggg","weekYear"),Hn("ggggg","weekYear"),Hn("GGGG","isoWeekYear"),Hn("GGGGG","isoWeekYear"),$("weekYear","gg"),$("isoWeekYear","GG"),W("weekYear",1),W("isoWeekYear",1),Q("G",Zr),Q("g",Zr),Q("GG",Jr,Ir),Q("gg",Jr,Ir),Q("GGGG",qr,Nr),Q("gggg",qr,Nr),Q("GGGGG",Br,zr),Q("ggggg",Br,zr),re(["gggg","ggggg","GGGG","GGGGG"],function(e,t,n,r){t[r.substr(0,2)]=L(e)}),re(["gg","GG"],function(e,n,r,a){n[a]=t.parseTwoDigitYear(e)}),G("Q",0,"Qo","quarter"),$("quarter","Q"),W("quarter",7),Q("Q",Wr),ne("Q",function(e,t){t[ia]=3*(L(e)-1)}),G("D",["DD",2],"Do","date"),$("date","D"),W("date",9),Q("D",Jr),Q("DD",Jr,Ir),Q("Do",function(e,t){return e?t._dayOfMonthOrdinalParse||t._ordinalParse:t._dayOfMonthOrdinalParseLenient}),ne(["D","DD"],oa),ne("Do",function(e,t){t[oa]=L(e.match(Jr)[0],10)});var Ka=R("Date",!0);G("DDD",["DDDD",3],"DDDo","dayOfYear"),$("dayOfYear","DDD"),W("dayOfYear",4),Q("DDD",Gr),Q("DDDD",Rr),ne(["DDD","DDDD"],function(e,t,n){n._dayOfYear=L(e)}),G("m",["mm",2],0,"minute"),$("minute","m"),W("minute",14),Q("m",Jr),Q("mm",Jr,Ir),ne(["m","mm"],ua);var Za=R("Minutes",!1);G("s",["ss",2],0,"second"),$("second","s"),W("second",15),Q("s",Jr),Q("ss",Jr,Ir),ne(["s","ss"],da);var Qa=R("Seconds",!1);G("S",0,0,function(){return~~(this.millisecond()/100)}),G(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),G(0,["SSS",3],0,"millisecond"),G(0,["SSSS",4],0,function(){return 10*this.millisecond()}),G(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),G(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),G(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),G(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),G(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),$("millisecond","ms"),W("millisecond",16),Q("S",Gr,Wr),Q("SS",Gr,Ir),Q("SSS",Gr,Rr);var Xa;for(Xa="SSSS";Xa.length<=9;Xa+="S")Q(Xa,Kr);for(Xa="S";Xa.length<=9;Xa+="S")ne(Xa,In);var ei=R("Milliseconds",!1);G("z",0,0,"zoneAbbr"),G("zz",0,0,"zoneName");var ti=v.prototype;ti.add=Ga,ti.calendar=Qt,ti.clone=Xt,ti.diff=sn,ti.endOf=gn,ti.format=_n,ti.from=fn,ti.fromNow=mn,ti.to=hn,ti.toNow=pn,ti.get=J,ti.invalidAt=jn,ti.isAfter=en,ti.isBefore=tn,ti.isBetween=nn,ti.isSame=rn,ti.isSameOrAfter=an,ti.isSameOrBefore=on,ti.isValid=Tn,ti.lang=Ba,ti.locale=yn,ti.localeData=vn,ti.max=Ra,ti.min=Ia,ti.parsingFlags=Sn,ti.set=U,ti.startOf=Mn,ti.subtract=qa,ti.toArray=bn,ti.toObject=wn,ti.toDate=kn,ti.toISOString=cn,ti.inspect=ln,ti.toJSON=Dn,ti.toString=dn,ti.unix=Yn,ti.valueOf=Ln,ti.creationData=xn,ti.year=Ma,ti.isLeapYear=ve,ti.weekYear=On,ti.isoWeekYear=An,ti.quarter=ti.quarters=Fn,ti.month=le,ti.daysInMonth=_e,ti.week=ti.weeks=Se,ti.isoWeek=ti.isoWeeks=je,ti.weeksInYear=Pn,ti.isoWeeksInYear=En,ti.date=Ka,ti.day=ti.days=Ce,ti.weekday=Fe,ti.isoWeekday=We,ti.dayOfYear=Wn,ti.hour=ti.hours=ja,ti.minute=ti.minutes=Za,ti.second=ti.seconds=Qa,ti.millisecond=ti.milliseconds=ei,ti.utcOffset=Et,ti.utc=$t,ti.local=Ct,ti.parseZone=Ft,ti.hasAlignedHourOffset=Wt,ti.isDST=It,ti.isLocal=Nt,ti.isUtcOffset=zt,ti.isUtc=Jt,ti.isUTC=Jt,ti.zoneAbbr=Rn,ti.zoneName=Nn,ti.dates=b("dates accessor is deprecated. Use date instead.",Ka),ti.months=b("months accessor is deprecated. Use month instead",le),ti.years=b("years accessor is deprecated. Use year instead",Ma),ti.zone=b("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",Pt),ti.isDSTShifted=b("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Rt);var ni=j.prototype;ni.calendar=x,ni.longDateFormat=H,ni.invalidDate=O,ni.ordinal=A,ni.preparse=Un,ni.postformat=Un,ni.relativeTime=E,ni.pastFuture=P,ni.set=T,ni.months=oe,ni.monthsShort=se,ni.monthsParse=de,ni.monthsRegex=me,ni.monthsShortRegex=fe,ni.week=we,ni.firstDayOfYear=Te,ni.firstDayOfWeek=De,ni.weekdays=Oe,ni.weekdaysMin=Ee,ni.weekdaysShort=Ae,ni.weekdaysParse=$e,ni.weekdaysRegex=Ie,ni.weekdaysShortRegex=Re,ni.weekdaysMinRegex=Ne,ni.isPM=qe,ni.meridiem=Be,Xe("en",{dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var t=e%10;return e+(1===L(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")}}),t.lang=b("moment.lang is deprecated. Use moment.locale instead.",Xe),t.langData=b("moment.langData is deprecated. Use moment.localeData instead.",nt);var ri=Math.abs,ai=cr("ms"),ii=cr("s"),oi=cr("m"),si=cr("h"),ui=cr("d"),di=cr("w"),ci=cr("M"),li=cr("y"),_i=_r("milliseconds"),fi=_r("seconds"),mi=_r("minutes"),hi=_r("hours"),pi=_r("days"),yi=_r("months"),vi=_r("years"),Mi=Math.round,gi={ss:44,s:45,m:45,h:22,d:26,M:11},Li=Math.abs,Yi=Tt.prototype;return Yi.isValid=wt,Yi.abs=er,Yi.add=nr,Yi.subtract=rr,Yi.as=ur,Yi.asMilliseconds=ai,Yi.asSeconds=ii,Yi.asMinutes=oi,Yi.asHours=si,Yi.asDays=ui,Yi.asWeeks=di,Yi.asMonths=ci,Yi.asYears=li,Yi.valueOf=dr,Yi._bubble=ir,Yi.get=lr,Yi.milliseconds=_i,Yi.seconds=fi,Yi.minutes=mi,Yi.hours=hi,Yi.days=pi,Yi.weeks=fr,Yi.months=yi,Yi.years=vi,Yi.humanize=vr,Yi.toISOString=Mr,Yi.toString=Mr,Yi.toJSON=Mr,Yi.locale=yn,Yi.localeData=vn,Yi.toIsoString=b("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Mr),Yi.lang=Ba,G("X",0,0,"unix"),G("x",0,0,"valueOf"),Q("x",Zr),Q("X",ea),ne("X",function(e,t,n){n._d=new Date(1e3*parseFloat(e,10))}),ne("x",function(e,t,n){n._d=new Date(L(e))}),t.version="2.18.1",function(e){gr=e}(gt),t.fn=ti,t.min=Yt,t.max=kt,t.now=Na,t.utc=_,t.unix=zn,t.months=Bn,t.isDate=u,t.locale=Xe,t.invalid=p,t.duration=Ut,t.isMoment=M,t.weekdays=Zn,t.parseZone=Jn,t.localeData=nt,t.isDuration=St,t.monthsShort=Kn,t.weekdaysMin=Xn,t.defineLocale=et,t.updateLocale=tt,t.locales=rt,t.weekdaysShort=Qn,t.normalizeUnits=C,t.relativeTimeRounding=pr,t.relativeTimeThreshold=yr,t.calendarFormat=Zt,t.prototype=ti,t})}).call(t,n(71)(e))},,,,,,,,,function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},,,,,,,,,,,function(e,t,n){(function(t){/*! * Vue.js v2.4.2 * (c) 2014-2017 Evan You * Released under the MIT License. */ !function(t,n){e.exports=n()}(0,function(){"use strict";function e(e){return void 0===e||null===e}function n(e){return void 0!==e&&null!==e}function r(e){return!0===e}function a(e){return!1===e}function i(e){return"string"==typeof e||"number"==typeof e||"boolean"==typeof e}function o(e){return null!==e&&"object"==typeof e}function s(e){return"[object Object]"===fa.call(e)}function u(e){return"[object RegExp]"===fa.call(e)}function d(e){var t=parseFloat(e);return t>=0&&Math.floor(t)===t&&isFinite(e)}function c(e){return null==e?"":"object"==typeof e?JSON.stringify(e,null,2):String(e)}function l(e){var t=parseFloat(e);return isNaN(t)?e:t}function _(e,t){for(var n=Object.create(null),r=e.split(","),a=0;a-1)return e.splice(n,1)}}function m(e,t){return pa.call(e,t)}function h(e){var t=Object.create(null);return function(n){return t[n]||(t[n]=e(n))}}function p(e,t){function n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}return n._length=e.length,n}function y(e,t){t=t||0;for(var n=e.length-t,r=new Array(n);n--;)r[n]=e[n+t];return r}function v(e,t){for(var n in t)e[n]=t[n];return e}function M(e){for(var t={},n=0;npi&&li[n].id>e.id;)n--;li.splice(n+1,0,e)}else li.push(e);mi||(mi=!0,qa(Se))}}function Ae(e){Mi.clear(),Ee(e,Mi)}function Ee(e,t){var n,r,a=Array.isArray(e);if((a||o(e))&&Object.isExtensible(e)){if(e.__ob__){var i=e.__ob__.dep.id;if(t.has(i))return;t.add(i)}if(a)for(n=e.length;n--;)Ee(e[n],t);else for(n=(r=Object.keys(e)).length;n--;)Ee(e[r[n]],t)}}function Pe(e,t,n){gi.get=function(){return this[t][n]},gi.set=function(e){this[t][n]=e},Object.defineProperty(e,n,gi)}function $e(e){e._watchers=[];var t=e.$options;t.props&&Ce(e,t.props),t.methods&&ze(e,t.methods),t.data?Fe(e):A(e._data={},!0),t.computed&&Ie(e,t.computed),t.watch&&t.watch!==Ia&&Je(e,t.watch)}function Ce(e,t){var n=e.$options.propsData||{},r=e._props={},a=e.$options._propKeys=[],i=!e.$parent;ti.shouldConvert=i;for(var o in t)!function(i){a.push(i);var o=G(i,t,n,e);E(r,i,o),i in e||Pe(e,"_props",i)}(o);ti.shouldConvert=!0}function Fe(e){var t=e.$options.data;s(t=e._data="function"==typeof t?We(t,e):t||{})||(t={});for(var n=Object.keys(t),r=e.$options.props,a=(e.$options.methods,n.length);a--;){var i=n[a];r&&m(r,i)||b(i)||Pe(e,"_data",i)}A(t,!0)}function We(e,t){try{return e.call(t)}catch(e){return T(e,t,"data()"),{}}}function Ie(e,t){var n=e._computedWatchers=Object.create(null);for(var r in t){var a=t[r],i="function"==typeof a?a:a.get;n[r]=new vi(e,i||g,g,Li),r in e||Re(e,r,a)}}function Re(e,t,n){"function"==typeof n?(gi.get=Ne(t),gi.set=g):(gi.get=n.get?!1!==n.cache?Ne(t):n.get:g,gi.set=n.set?n.set:g),Object.defineProperty(e,t,gi)}function Ne(e){return function(){var t=this._computedWatchers&&this._computedWatchers[e];if(t)return t.dirty&&t.evaluate(),Ka.target&&t.depend(),t.value}}function ze(e,t){e.$options.props;for(var n in t)e[n]=null==t[n]?g:p(t[n],e)}function Je(e,t){for(var n in t){var r=t[n];if(Array.isArray(r))for(var a=0;a=0||n.indexOf(e[a])<0)&&r.push(e[a]);return r}return e}function gt(e){this._init(e)}function Lt(e){e.use=function(e){var t=this._installedPlugins||(this._installedPlugins=[]);if(t.indexOf(e)>-1)return this;var n=y(arguments,1);return n.unshift(this),"function"==typeof e.install?e.install.apply(e,n):"function"==typeof e&&e.apply(null,n),t.push(e),this}}function Yt(e){e.mixin=function(e){return this.options=U(this.options,e),this}}function kt(e){e.cid=0;var t=1;e.extend=function(e){e=e||{};var n=this,r=n.cid,a=e._Ctor||(e._Ctor={});if(a[r])return a[r];var i=e.name||n.options.name,o=function(e){this._init(e)};return o.prototype=Object.create(n.prototype),o.prototype.constructor=o,o.cid=t++,o.options=U(n.options,e),o.super=n,o.options.props&&bt(o),o.options.computed&&wt(o),o.extend=n.extend,o.mixin=n.mixin,o.use=n.use,wa.forEach(function(e){o[e]=n[e]}),i&&(o.options.components[i]=o),o.superOptions=n.options,o.extendOptions=e,o.sealedOptions=v({},o.options),a[r]=o,o}}function bt(e){var t=e.options.props;for(var n in t)Pe(e.prototype,"_props",n)}function wt(e){var t=e.options.computed;for(var n in t)Re(e.prototype,n,t[n])}function Dt(e){wa.forEach(function(t){e[t]=function(e,n){return n?("component"===t&&s(n)&&(n.name=n.name||e,n=this.options._base.extend(n)),"directive"===t&&"function"==typeof n&&(n={bind:n,update:n}),this.options[t+"s"][e]=n,n):this.options[t+"s"][e]}})}function Tt(e){return e&&(e.Ctor.options.name||e.tag)}function St(e,t){return Array.isArray(e)?e.indexOf(t)>-1:"string"==typeof e?e.split(",").indexOf(t)>-1:!!u(e)&&e.test(t)}function jt(e,t,n){for(var r in e){var a=e[r];if(a){var i=Tt(a.componentOptions);i&&!n(i)&&(a!==t&&xt(a),e[r]=null)}}}function xt(e){e&&e.componentInstance.$destroy()}function Ht(e){for(var t=e.data,r=e,a=e;n(a.componentInstance);)(a=a.componentInstance._vnode).data&&(t=Ot(a.data,t));for(;n(r=r.parent);)r.data&&(t=Ot(t,r.data));return At(t.staticClass,t.class)}function Ot(e,t){return{staticClass:Et(e.staticClass,t.staticClass),class:n(e.class)?[e.class,t.class]:t.class}}function At(e,t){return n(e)||n(t)?Et(e,Pt(t)):""}function Et(e,t){return e?t?e+" "+t:e:t||""}function Pt(e){return Array.isArray(e)?$t(e):o(e)?Ct(e):"string"==typeof e?e:""}function $t(e){for(var t,r="",a=0,i=e.length;a=0&&" "===(p=e.charAt(h));h--);p&&so.test(p)||(c=!0)}}else void 0===i?(m=a+1,i=e.slice(0,a).trim()):t();if(void 0===i?i=e.slice(0,a).trim():0!==m&&t(),o)for(a=0;a=ji}function mn(e){return 34===e||39===e}function hn(e){var t=1;for(Ai=Oi;!fn();)if(e=_n(),mn(e))pn(e);else if(91===e&&t++,93===e&&t--,0===t){Ei=Oi;break}}function pn(e){for(var t=e;!fn()&&(e=_n())!==t;);}function yn(e,t,n){var r=n&&n.number,a=sn(e,"value")||"null",i=sn(e,"true-value")||"true",o=sn(e,"false-value")||"false";nn(e,"checked","Array.isArray("+t+")?_i("+t+","+a+")>-1"+("true"===i?":("+t+")":":_q("+t+","+i+")")),on(e,co,"var $$a="+t+",$$el=$event.target,$$c=$$el.checked?("+i+"):("+o+");if(Array.isArray($$a)){var $$v="+(r?"_n("+a+")":a)+",$$i=_i($$a,$$v);if($$el.checked){$$i<0&&("+t+"=$$a.concat($$v))}else{$$i>-1&&("+t+"=$$a.slice(0,$$i).concat($$a.slice($$i+1)))}}else{"+cn(t,"$$c")+"}",null,!0)}function vn(e,t,n){var r=n&&n.number,a=sn(e,"value")||"null";nn(e,"checked","_q("+t+","+(a=r?"_n("+a+")":a)+")"),on(e,co,cn(t,a),null,!0)}function Mn(e,t,n){var r='var $$selectedVal = Array.prototype.filter.call($event.target.options,function(o){return o.selected}).map(function(o){var val = "_value" in o ? o._value : o.value;return '+(n&&n.number?"_n(val)":"val")+"});";on(e,"change",r=r+" "+cn(t,"$event.target.multiple ? $$selectedVal : $$selectedVal[0]"),null,!0)}function gn(e,t,n){var r=e.attrsMap.type,a=n||{},i=a.lazy,o=a.number,s=a.trim,u=!i&&"range"!==r,d=i?"change":"range"===r?uo:"input",c="$event.target.value";s&&(c="$event.target.value.trim()"),o&&(c="_n("+c+")");var l=cn(t,c);u&&(l="if($event.target.composing)return;"+l),nn(e,"value","("+t+")"),on(e,d,l,null,!0),(s||o)&&on(e,"blur","$forceUpdate()")}function Ln(e){var t;n(e[uo])&&(e[t=Ea?"change":"input"]=[].concat(e[uo],e[t]||[]),delete e[uo]),n(e[co])&&(e[t=Wa?"click":"change"]=[].concat(e[co],e[t]||[]),delete e[co])}function Yn(e,t,n,r,a){if(n){var i=t,o=$i;t=function(n){null!==(1===arguments.length?i(n):i.apply(null,arguments))&&kn(e,t,r,o)}}$i.addEventListener(e,t,Ra?{capture:r,passive:a}:r)}function kn(e,t,n,r){(r||$i).removeEventListener(e,t,n)}function bn(t,n){if(!e(t.data.on)||!e(n.data.on)){var r=n.data.on||{},a=t.data.on||{};$i=n.elm,Ln(r),te(r,a,Yn,kn,n.context)}}function wn(t,r){if(!e(t.data.domProps)||!e(r.data.domProps)){var a,i,o=r.elm,s=t.data.domProps||{},u=r.data.domProps||{};n(u.__ob__)&&(u=r.data.domProps=v({},u));for(a in s)e(u[a])&&(o[a]="");for(a in u)if(i=u[a],"textContent"!==a&&"innerHTML"!==a||(r.children&&(r.children.length=0),i!==s[a]))if("value"===a){o._value=i;var d=e(i)?"":String(i);Dn(o,r,d)&&(o.value=d)}else o[a]=i}}function Dn(e,t,n){return!e.composing&&("option"===t.tag||Tn(e,n)||Sn(e,n))}function Tn(e,t){var n=!0;try{n=document.activeElement!==e}catch(e){}return n&&e.value!==t}function Sn(e,t){var r=e.value,a=e._vModifiers;return n(a)&&a.number?l(r)!==l(t):n(a)&&a.trim?r.trim()!==t.trim():r!==t}function jn(e){var t=xn(e.style);return e.staticStyle?v(e.staticStyle,t):t}function xn(e){return Array.isArray(e)?M(e):"string"==typeof e?fo(e):e}function Hn(e,t){var n,r={};if(t)for(var a=e;a.componentInstance;)(a=a.componentInstance._vnode).data&&(n=jn(a.data))&&v(r,n);(n=jn(e.data))&&v(r,n);for(var i=e;i=i.parent;)i.data&&(n=jn(i.data))&&v(r,n);return r}function On(t,r){var a=r.data,i=t.data;if(!(e(a.staticStyle)&&e(a.style)&&e(i.staticStyle)&&e(i.style))){var o,s,u=r.elm,d=i.staticStyle,c=i.normalizedStyle||i.style||{},l=d||c,_=xn(r.data.style)||{};r.data.normalizedStyle=n(_.__ob__)?v({},_):_;var f=Hn(r,!0);for(s in l)e(f[s])&&po(u,s,"");for(s in f)(o=f[s])!==l[s]&&po(u,s,null==o?"":o)}}function An(e,t){if(t&&(t=t.trim()))if(e.classList)t.indexOf(" ")>-1?t.split(/\s+/).forEach(function(t){return e.classList.add(t)}):e.classList.add(t);else{var n=" "+(e.getAttribute("class")||"")+" ";n.indexOf(" "+t+" ")<0&&e.setAttribute("class",(n+t).trim())}}function En(e,t){if(t&&(t=t.trim()))if(e.classList)t.indexOf(" ")>-1?t.split(/\s+/).forEach(function(t){return e.classList.remove(t)}):e.classList.remove(t),e.classList.length||e.removeAttribute("class");else{for(var n=" "+(e.getAttribute("class")||"")+" ",r=" "+t+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?e.setAttribute("class",n):e.removeAttribute("class")}}function Pn(e){if(e){if("object"==typeof e){var t={};return!1!==e.css&&v(t,go(e.name||"v")),v(t,e),t}return"string"==typeof e?go(e):void 0}}function $n(e){So(function(){So(e)})}function Cn(e,t){var n=e._transitionClasses||(e._transitionClasses=[]);n.indexOf(t)<0&&(n.push(t),An(e,t))}function Fn(e,t){e._transitionClasses&&f(e._transitionClasses,t),En(e,t)}function Wn(e,t,n){var r=In(e,t),a=r.type,i=r.timeout,o=r.propCount;if(!a)return n();var s=a===Yo?wo:To,u=0,d=function(){e.removeEventListener(s,c),n()},c=function(t){t.target===e&&++u>=o&&d()};setTimeout(function(){u0&&(n=Yo,c=o,l=i.length):t===ko?d>0&&(n=ko,c=d,l=u.length):l=(n=(c=Math.max(o,d))>0?o>d?Yo:ko:null)?n===Yo?i.length:u.length:0,{type:n,timeout:c,propCount:l,hasTransform:n===Yo&&jo.test(r[bo+"Property"])}}function Rn(e,t){for(;e.length1}function Gn(e,t){!0!==t.data.show&&zn(t)}function qn(e,t,n){var r=t.value,a=e.multiple;if(!a||Array.isArray(r)){for(var i,o,s=0,u=e.options.length;s-1,o.selected!==i&&(o.selected=i);else if(L(Bn(o),r))return void(e.selectedIndex!==s&&(e.selectedIndex=s));a||(e.selectedIndex=-1)}}function Bn(e){return"_value"in e?e._value:e.value}function Kn(e){e.target.composing=!0}function Zn(e){e.target.composing&&(e.target.composing=!1,Qn(e.target,"input"))}function Qn(e,t){var n=document.createEvent("HTMLEvents");n.initEvent(t,!0,!0),e.dispatchEvent(n)}function Xn(e){return!e.componentInstance||e.data&&e.data.transition?e:Xn(e.componentInstance._vnode)}function er(e){var t=e&&e.componentOptions;return t&&t.Ctor.options.abstract?er(_e(t.children)):e}function tr(e){var t={},n=e.$options;for(var r in n.propsData)t[r]=e[r];var a=n._parentListeners;for(var i in a)t[va(i)]=a[i];return t}function nr(e,t){if(/\d-keep-alive$/.test(t.tag))return e("keep-alive",{props:t.componentOptions.propsData})}function rr(e){for(;e=e.parent;)if(e.data.transition)return!0}function ar(e,t){return t.key===e.key&&t.tag===e.tag}function ir(e){return e.isComment&&e.asyncFactory}function or(e){e.elm._moveCb&&e.elm._moveCb(),e.elm._enterCb&&e.elm._enterCb()}function sr(e){e.data.newPos=e.elm.getBoundingClientRect()}function ur(e){var t=e.data.pos,n=e.data.newPos,r=t.left-n.left,a=t.top-n.top;if(r||a){e.data.moved=!0;var i=e.elm.style;i.transform=i.WebkitTransform="translate("+r+"px,"+a+"px)",i.transitionDuration="0s"}}function dr(e,t){var n=t?Ro(t):Wo;if(n.test(e)){for(var r,a,i=[],o=n.lastIndex=0;r=n.exec(e);){(a=r.index)>o&&i.push(JSON.stringify(e.slice(o,a)));var s=Qt(r[1].trim());i.push("_s("+s+")"),o=a+r[0].length}return o=0&&o[a].lowerCasedTag!==s;a--);else a=0;if(a>=0){for(var u=o.length-1;u>=a;u--)t.end&&t.end(o[u].tag,n,r);o.length=a,i=a&&o[a-1].tag}else"br"===s?t.start&&t.start(e,[],!0,n,r):"p"===s&&(t.start&&t.start(e,[],!1,n,r),t.end&&t.end(e,n,r))}for(var a,i,o=[],s=t.expectHTML,u=t.isUnaryTag||Ya,d=t.canBeLeftOpenTag||Ya,c=0;e;){if(a=e,i&&vs(i)){var l=0,_=i.toLowerCase(),f=Ms[_]||(Ms[_]=new RegExp("([\\s\\S]*?)(]*>)","i")),m=e.replace(f,function(e,n,r){return l=r.length,vs(_)||"noscript"===_||(n=n.replace(//g,"$1").replace(//g,"$1")),bs(_,n)&&(n=n.slice(1)),t.chars&&t.chars(n),""});c+=e.length-m.length,e=m,r(_,c-l,c)}else{var h=e.indexOf("<");if(0===h){if(is.test(e)){var p=e.indexOf("--\x3e");if(p>=0){t.shouldKeepComment&&t.comment(e.substring(4,p)),n(p+3);continue}}if(os.test(e)){var y=e.indexOf("]>");if(y>=0){n(y+2);continue}}var v=e.match(as);if(v){n(v[0].length);continue}var M=e.match(rs);if(M){var g=c;n(M[0].length),r(M[1],g,c);continue}var L=function(){var t=e.match(ts);if(t){var r={tagName:t[1],attrs:[],start:c};n(t[0].length);for(var a,i;!(a=e.match(ns))&&(i=e.match(Qo));)n(i[0].length),r.attrs.push(i);if(a)return r.unarySlash=a[1],n(a[0].length),r.end=c,r}}();if(L){!function(e){var n=e.tagName,a=e.unarySlash;s&&("p"===i&&Vo(n)&&r(i),d(n)&&i===n&&r(n));for(var c=u(n)||!!a,l=e.attrs.length,_=new Array(l),f=0;f=0){for(k=e.slice(h);!(rs.test(k)||ts.test(k)||is.test(k)||os.test(k)||(b=k.indexOf("<",1))<0);)h+=b,k=e.slice(h);Y=e.substring(0,h),n(h)}h<0&&(Y=e,e=""),t.chars&&Y&&t.chars(Y)}if(e===a){t.chars&&t.chars(e);break}}r()}function _r(e,t){function n(e){e.pre&&(s=!1),fs(e.tag)&&(u=!1)}us=t.warn||en,fs=t.isPreTag||Ya,ms=t.mustUseProp||Ya,hs=t.getTagNamespace||Ya,cs=tn(t.modules,"transformNode"),ls=tn(t.modules,"preTransformNode"),_s=tn(t.modules,"postTransformNode"),ds=t.delimiters;var r,a,i=[],o=!1!==t.preserveWhitespace,s=!1,u=!1;return lr(e,{warn:us,expectHTML:t.expectHTML,isUnaryTag:t.isUnaryTag,canBeLeftOpenTag:t.canBeLeftOpenTag,shouldDecodeNewlines:t.shouldDecodeNewlines,shouldKeepComment:t.comments,start:function(e,o,d){var c=a&&a.ns||hs(e);Ea&&"svg"===c&&(o=Hr(o));var l={type:1,tag:e,attrsList:o,attrsMap:Sr(o),parent:a,children:[]};c&&(l.ns=c),xr(l)&&!Ua()&&(l.forbidden=!0);for(var _=0;_0,$a=Aa&&Aa.indexOf("edge/")>0,Ca=Aa&&Aa.indexOf("android")>0,Fa=Aa&&/iphone|ipad|ipod|ios/.test(Aa),Wa=Aa&&/chrome\/\d+/.test(Aa)&&!$a,Ia={}.watch,Ra=!1;if(Oa)try{var Na={};Object.defineProperty(Na,"passive",{get:function(){Ra=!0}}),window.addEventListener("test-passive",null,Na)}catch(e){}var za,Ja,Ua=function(){return void 0===za&&(za=!Oa&&void 0!==t&&"server"===t.process.env.VUE_ENV),za},Va=Oa&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__,Ga="undefined"!=typeof Symbol&&S(Symbol)&&"undefined"!=typeof Reflect&&S(Reflect.ownKeys),qa=function(){function e(){r=!1;var e=n.slice(0);n.length=0;for(var t=0;t1?y(n):n;for(var r=y(arguments,1),a=0,i=n.length;a1&&(t[n[0].trim()]=n[1].trim())}}),t}),mo=/^--/,ho=/\s*!important$/,po=function(e,t,n){if(mo.test(t))e.style.setProperty(t,n);else if(ho.test(n))e.style.setProperty(t,n.replace(ho,""),"important");else{var r=vo(t);if(Array.isArray(n))for(var a=0,i=n.length;af?v(t,e(a[p+1])?null:a[p+1].elm,a,_,p,i):_>p&&g(t,r,l,f)}function k(t,a,i,o){if(t!==a){var s=a.elm=t.elm;if(r(t.isAsyncPlaceholder))n(a.asyncFactory.resolved)?w(t.elm,a,i):a.isAsyncPlaceholder=!0;else if(r(a.isStatic)&&r(t.isStatic)&&a.key===t.key&&(r(a.isCloned)||r(a.isOnce)))a.componentInstance=t.componentInstance;else{var u,d=a.data;n(d)&&n(u=d.hook)&&n(u=u.prepatch)&&u(t,a);var c=t.children,l=a.children;if(n(d)&&h(a)){for(u=0;u-1?Zi[e]=t.constructor===window.HTMLUnknownElement||t.constructor===window.HTMLElement:Zi[e]=/HTMLUnknownElement/.test(t.toString())},v(gt.options.directives,Oo),v(gt.options.components,$o),gt.prototype.__patch__=Oa?xo:g,gt.prototype.$mount=function(e,t){return e=e&&Oa?Wt(e):void 0,Le(this,e,t)},setTimeout(function(){Ta.devtools&&Va&&Va.emit("init",gt)},0);var Co,Fo=!!Oa&&function(e,t){var n=document.createElement("div");return n.innerHTML='
',n.innerHTML.indexOf(" ")>0}(),Wo=/\{\{((?:.|\n)+?)\}\}/g,Io=/[-.*+?^${}()|[\]\/\\]/g,Ro=h(function(e){var t=e[0].replace(Io,"\\$&"),n=e[1].replace(Io,"\\$&");return new RegExp(t+"((?:.|\\n)+?)"+n,"g")}),No=[{staticKeys:["staticClass"],transformNode:function(e,t){t.warn;var n=un(e,"class");n&&(e.staticClass=JSON.stringify(n));var r=sn(e,"class",!1);r&&(e.classBinding=r)},genData:function(e){var t="";return e.staticClass&&(t+="staticClass:"+e.staticClass+","),e.classBinding&&(t+="class:"+e.classBinding+","),t}},{staticKeys:["staticStyle"],transformNode:function(e,t){t.warn;var n=un(e,"style");n&&(e.staticStyle=JSON.stringify(fo(n)));var r=sn(e,"style",!1);r&&(e.styleBinding=r)},genData:function(e){var t="";return e.staticStyle&&(t+="staticStyle:"+e.staticStyle+","),e.styleBinding&&(t+="style:("+e.styleBinding+"),"),t}}],zo={model:function(e,t,n){Pi=n;var r=t.value,a=t.modifiers,i=e.tag,o=e.attrsMap.type;if(e.component)return dn(e,r,a),!1;if("select"===i)Mn(e,r,a);else if("input"===i&&"checkbox"===o)yn(e,r,a);else if("input"===i&&"radio"===o)vn(e,r,a);else if("input"===i||"textarea"===i)gn(e,r,a);else if(!Ta.isReservedTag(i))return dn(e,r,a),!1;return!0},text:function(e,t){t.value&&nn(e,"textContent","_s("+t.value+")")},html:function(e,t){t.value&&nn(e,"innerHTML","_s("+t.value+")")}},Jo=_("area,base,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"),Uo=_("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),Vo=_("address,article,aside,base,blockquote,body,caption,col,colgroup,dd,details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,title,tr,track"),Go={expectHTML:!0,modules:No,directives:zo,isPreTag:function(e){return"pre"===e},isUnaryTag:Jo,mustUseProp:Ii,canBeLeftOpenTag:Uo,isReservedTag:Ki,getTagNamespace:Ft,staticKeys:function(e){return e.reduce(function(e,t){return e.concat(t.staticKeys||[])},[]).join(",")}(No)},qo={decode:function(e){return Co=Co||document.createElement("div"),Co.innerHTML=e,Co.textContent}},Bo=/([^\s"'<>\/=]+)/,Ko=/(?:=)/,Zo=[/"([^"]*)"+/.source,/'([^']*)'+/.source,/([^\s"'=<>`]+)/.source],Qo=new RegExp("^\\s*"+Bo.source+"(?:\\s*("+Ko.source+")\\s*(?:"+Zo.join("|")+"))?"),Xo="[a-zA-Z_][\\w\\-\\.]*",es="((?:"+Xo+"\\:)?"+Xo+")",ts=new RegExp("^<"+es),ns=/^\s*(\/?)>/,rs=new RegExp("^<\\/"+es+"[^>]*>"),as=/^]+>/i,is=/^