├── .gitignore ├── .npmignore ├── .travis.yml ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── LICENSE ├── README.md ├── TODO.md ├── bin └── dtsmake ├── example ├── dist │ ├── clone.d.ts │ ├── deeplib.d.ts │ ├── gulp-concat.d.ts │ ├── gulp-header.d.ts │ ├── mylib.d.ts │ ├── sinon.d.ts │ └── tern.d.ts ├── example.js ├── package.json ├── src │ ├── deeplib.js │ └── mylib.js └── test │ ├── fixture │ ├── gulp-concat-sample.js │ └── node.d.ts │ ├── mylib-test.ts │ └── tern-test.ts ├── gulpfile.ts ├── package.json ├── sample ├── infer.js.json ├── sample.json └── tern.js.json ├── src ├── dtsmake.ts └── index.ts ├── test ├── dtsout-test.ts ├── example-test.ts ├── file-test.ts └── parse-test.ts ├── tsconfig.json └── typings ├── clone └── clone.d.ts ├── empower └── empower.d.ts ├── mocha └── mocha.d.ts ├── node └── node.d.ts ├── power-assert-formatter └── power-assert-formatter.d.ts ├── power-assert └── power-assert.d.ts └── sinon └── sinon.d.ts /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | tmp 5 | lib 6 | .tmp 7 | typings -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | typings 3 | tmp 4 | tsconfig.json 5 | tsd.json 6 | TODO.md 7 | gulpfile.ts 8 | sample 9 | example 10 | test 11 | .tmp 12 | .settings 13 | .travis.yml 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.12 -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "extest1", 11 | "program": "${workspaceRoot}/example/node_modules/dtsmake/lib/index.js", 12 | "cwd": "${workspaceRoot}", 13 | "args": [ 14 | "-s","${workspaceRoot}/node_modules/sinon/pkg/sinon.js", 15 | "--dist","${workspaceRoot}/example/dist/sinon" 16 | ], 17 | "sourceMaps": false 18 | }, 19 | { 20 | "type": "node", 21 | "request": "launch", 22 | "name": "Run with mocha", 23 | "program": "${workspaceRoot}/node_modules/mocha/bin/mocha", 24 | "cwd": "${workspaceRoot}", 25 | "args": ["--compilers","ts:espower-typescript/guess","test/*-test.ts"], 26 | "sourceMaps": false 27 | }, 28 | { 29 | "type": "node", 30 | "request": "launch", 31 | "name": "プログラムの起動", 32 | "program": "${workspaceRoot}\\lib\\dtsmake.js", 33 | "cwd": "${workspaceRoot}" 34 | }, 35 | { 36 | "type": "node", 37 | "request": "attach", 38 | "name": "プロセスに添付", 39 | "port": 5858 40 | } 41 | ] 42 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // 既定の設定とユーザー設定を上書きするには、このファイル内に設定を挿入します 2 | { 3 | "files.eol": "\n" 4 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | 9 | // A task runner that calls the Typescipt compiler (tsc) and 10 | // Compiles a HelloWorld.ts program 11 | { 12 | "version": "0.1.0", 13 | 14 | // The command is tsc. Assumes that tsc has been installed using npm install -g typescript 15 | "command": "tsc", 16 | 17 | // The command is a shell script 18 | "isShellCommand": true, 19 | 20 | // Show the output window only if unrecognized errors occur. 21 | "showOutput": "silent", 22 | 23 | // args is the HelloWorld program to compile. 24 | "args": ["-p", "."], 25 | 26 | // use the standard tsc problem matcher to find compile problems 27 | // in the output. 28 | "problemMatcher": "$tsc" 29 | } 30 | 31 | // A task runner that calls the Typescipt compiler (tsc) and 32 | // compiles based on a tsconfig.json file that is present in 33 | // the root of the folder open in VSCode 34 | /* 35 | { 36 | "version": "0.1.0", 37 | 38 | // The command is tsc. Assumes that tsc has been installed using npm install -g typescript 39 | "command": "tsc", 40 | 41 | // The command is a shell script 42 | "isShellCommand": true, 43 | 44 | // Show the output window only if unrecognized errors occur. 45 | "showOutput": "silent", 46 | 47 | // Tell the tsc compiler to use the tsconfig.json from the open folder. 48 | "args": ["-p", "."], 49 | 50 | // use the standard tsc problem matcher to find compile problems 51 | // in the output. 52 | "problemMatcher": "$tsc" 53 | } 54 | */ 55 | 56 | 57 | // A task runner configuration for gulp. Gulp provides a less task 58 | // which compiles less to css. 59 | /* 60 | { 61 | "version": "0.1.0", 62 | "command": "gulp", 63 | "isShellCommand": true, 64 | "tasks": [ 65 | { 66 | "taskName": "less", 67 | // Make this the default build command. 68 | "isBuildCommand": true, 69 | // Show the output window only if unrecognized errors occur. 70 | "showOutput": "silent", 71 | // Use the standard less compilation problem matcher. 72 | "problemMatcher": "$lessCompile" 73 | } 74 | ] 75 | } 76 | */ 77 | 78 | // Uncomment the following section to use gulp in a watching mode that compiles a 79 | // less file. The gulp task prints "[hh:mm:ss] Starting 'clean-styles'" to the console 80 | // when existing css files get deleted and "[hh:mm:ss] Finished 'styles'" when the 81 | // overall less compilation has finished. When the clean pattern is detect internal less 82 | // problems are cleaned. When the finshed pattern is detected in the output less 83 | // problems are published. 84 | /* 85 | { 86 | "version": "0.1.0", 87 | "command": "gulp", 88 | "isShellCommand": true, 89 | "tasks": [ 90 | { 91 | "taskName": "watch-less", 92 | // Make this the default build command. 93 | "isBuildCommand": true, 94 | // Show the output window only if unrecognized errors occur. 95 | "showOutput": "silent", 96 | // Task is running in watching mode. 97 | "isWatching": true, 98 | "problemMatcher": { 99 | // Use the standard less compilation problem matcher as the base. 100 | "base": "$lessCompile", 101 | // A regular expression signalling that a watched task begins executing (usually triggered through file watching). 102 | "watchedTaskBeginsRegExp": "^\\[\\d+:\\d+:\\d+\\] Starting 'clean-styles'\\.\\.\\.$", 103 | // A regular expression signalling that a watched tasks ends executing. 104 | "watchedTaskEndsRegExp": "^\\[\\d+:\\d+:\\d+\\] Finished 'styles' after \\d+" 105 | } 106 | } 107 | ] 108 | } 109 | */ 110 | 111 | // Uncomment the following section to use jake to build a workspace 112 | // cloned from https://github.com/Microsoft/TypeScript.git 113 | /* 114 | { 115 | "version": "0.1.0", 116 | // Task runner is jake 117 | "command": "jake", 118 | // Need to be executed in shell / cmd 119 | "isShellCommand": true, 120 | "showOutput": "silent", 121 | "tasks": [ 122 | { 123 | // TS build command is local. 124 | "taskName": "local", 125 | // Make this the default build command. 126 | "isBuildCommand": true, 127 | // Show the output window only if unrecognized errors occur. 128 | "showOutput": "silent", 129 | // Use the redefined Typescript output problem matcher. 130 | "problemMatcher": [ 131 | "$tsc" 132 | ] 133 | } 134 | ] 135 | } 136 | */ 137 | 138 | // Uncomment the section below to use msbuild and generate problems 139 | // for csc, cpp, tsc and vb. The configuration assumes that msbuild 140 | // is available on the path and a solution file exists in the 141 | // workspace folder root. 142 | /* 143 | { 144 | "version": "0.1.0", 145 | "command": "msbuild", 146 | "args": [ 147 | // Ask msbuild to generate full paths for file names. 148 | "/property:GenerateFullPaths=true" 149 | ], 150 | "taskSelector": "/t:", 151 | "showOutput": "silent", 152 | "tasks": [ 153 | { 154 | "taskName": "build", 155 | // Show the output window only if unrecognized errors occur. 156 | "showOutput": "silent", 157 | // Use the standard MS compiler pattern to detect errors, warnings 158 | // and infos in the output. 159 | "problemMatcher": "$msCompile" 160 | } 161 | ] 162 | } 163 | */ 164 | 165 | // Uncomment the following section to use msbuild which compiles Typescript 166 | // and less files. 167 | /* 168 | { 169 | "version": "0.1.0", 170 | "command": "msbuild", 171 | "args": [ 172 | // Ask msbuild to generate full paths for file names. 173 | "/property:GenerateFullPaths=true" 174 | ], 175 | "taskSelector": "/t:", 176 | "showOutput": "silent", 177 | "tasks": [ 178 | { 179 | "taskName": "build", 180 | // Show the output window only if unrecognized errors occur. 181 | "showOutput": "silent", 182 | // Use the standard MS compiler pattern to detect errors, warnings 183 | // and infos in the output. 184 | "problemMatcher": [ 185 | "$msCompile", 186 | "$lessCompile" 187 | ] 188 | } 189 | ] 190 | } 191 | */ 192 | // A task runner example that defines a problemMatcher inline instead of using 193 | // a predfined one. 194 | /* 195 | { 196 | "version": "0.1.0", 197 | "command": "tsc", 198 | "isShellCommand": true, 199 | "args": ["HelloWorld.ts"], 200 | "showOutput": "silent", 201 | "problemMatcher": { 202 | // The problem is owned by the typescript language service. Ensure that the problems 203 | // are merged with problems produced by Visual Studio's language service. 204 | "owner": "typescript", 205 | // The file name for reported problems is relative to the current working directory. 206 | "fileLocation": ["relative", "${cwd}"], 207 | // The actual pattern to match problems in the output. 208 | "pattern": { 209 | // The regular expression. Matches HelloWorld.ts(2,10): error TS2339: Property 'logg' does not exist on type 'Console'. 210 | "regexp": "^([^\\s].*)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$", 211 | // The match group that denotes the file containing the problem. 212 | "file": 1, 213 | // The match group that denotes the problem location. 214 | "location": 2, 215 | // The match group that denotes the problem's severity. Can be omitted. 216 | "severity": 3, 217 | // The match group that denotes the problem code. Can be omitted. 218 | "code": 4, 219 | // The match group that denotes the problem's message. 220 | "message": 5 221 | } 222 | } 223 | } 224 | */ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ConquestArrow 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dtsmake 2 | ==== 3 | 4 | [TypeScript](http://www.typescriptlang.org/)'s type definition file (*.d.ts files) generator tool from JavaScript files. 5 | 6 | [![Build Status](https://travis-ci.org/ConquestArrow/dtsmake.svg?branch=master)](https://travis-ci.org/ConquestArrow/dtsmake) [![NPM version](https://badge.fury.io/js/dtsmake.svg)](http://badge.fury.io/js/dtsmake) [![Dependency status](https://david-dm.org/ConquestArrow/dtsmake.svg)](https://david-dm.org/ConquestArrow/dtsmake#info=dependencies&view=table) 7 | 8 | ## Description 9 | 10 | [TypeScript](http://www.typescriptlang.org/)'s type definition file (`*.d.ts` files) generator tool from JavaScript files. This tool is **WIP** (Work In Progress). 11 | 12 | A Japanese document: [TypeScript型定義ファイルのコツと生成ツール dtsmake](http://qiita.com/ConquestArrow/items/450f961c3d54bc932cf3) 13 | 14 | ### Features 15 | 16 | * Generating a `*.d.ts` file from a JavaScript file. 17 | * Type inference powered by [TernJS](http://ternjs.net/). (Need some sample JS files.) 18 | * Auto annotation JSDoc style comments. 19 | * Original JSDoc comment in base JS code output. 20 | * Header template output. 21 | 22 | ## VS. 23 | 24 | * [dtsgenerator](https://github.com/horiuchi/dtsgenerator) - d.ts file generator tool, for only JSON Schema files. 25 | * [js2tsd](https://github.com/mhelvens/js2tsd) - d.ts file generator tool, no type inferrence. 26 | * [JS2TSD](http://nekok.com/2014/05/javascript-to-typescript-type-definitions-d-ts-auto-converter/) d.ts file generator GUI tool app. Not CLI. 27 | 28 | ## Requirement 29 | 30 | Node.js 31 | 32 | ## Install 33 | 34 | `npm i dtsmake -g` 35 | 36 | ## Usage 37 | 38 | simple case: 39 | ``` 40 | dtsmake -s ./path/to/sourcefile.js 41 | ``` 42 | other case: 43 | ``` 44 | dtsmake -s ./path/to/src/target.js --dist ./path/to/dist/mydefinition -n "mydefinition" -p node -e -S "legacy" -M "MyDefinition" -x "./path/to/extrafile1.js,./path/to/extrafile2.js" -N --def ./path/to/def/ecma6 -A -i -a -g 45 | ``` 46 | 47 | ### Example 48 | 49 | 50 | * more usage examples -> [/example/example.js](./example/example.js) 51 | * generated TS definition files examples -> [/example/dist/](./example/dist/) 52 | 53 | ### Best Practice 54 | 55 | #### Generating Gulp.js plugin definition files 56 | 57 | `dtsmake -s /path/to/gulp/any/plugin.js -n "canalCasePluginName" -p node -e -M "gulp-*" -N -l "/path/to/node.d.ts"` 58 | 59 | * `-n "canalCasePluginName"` 60 | * gulp.js plugins has a name as `gulp-*`. 61 | * but, this is a invalid namespace name in TS. 62 | * so, naming canal case. 63 | * ex. `gulp-header` -> `gulpHeader` 64 | * or valid namespace name. 65 | * `-M "gulp-*"` 66 | * no need to name canal case. 67 | * `-p node` 68 | * use nodejs plugin of tern server. 69 | * `-N` 70 | * set nodejs module option ON 71 | * `-e` 72 | * set export option ON 73 | * `-l "/path/to/node.d.ts"` 74 | * add referrece path to node.d.ts definition file 75 | 76 | 77 | ### Options 78 | 79 | #### -h, --help 80 | output usage information 81 | #### -v, --version 82 | output the version number 83 | #### -s, --src `` 84 | __[MUST]__ target javascript file path 85 | #### --dist [value] 86 | outout d.ts file path. no need `.d.ts` file extension. 87 | 88 | ex. `--dist /path/to/dist` -> `/path/to/dist.d.ts` 89 | 90 | #### -n, --n [value] 91 | module name 92 | #### -p, --plugin `` 93 | tern.js plugin. 94 | 95 | * see [tern.js server plugin](http://ternjs.net/doc/manual.html#plugins) 96 | * [currently support plugins](https://github.com/marijnh/tern/tree/0.14.0/plugin) 97 | 98 | ex. `-p "node,module,commonjs"` 99 | 100 | #### -d, --def `` 101 | tern.js def files. DEFAULT:'ecma5' 102 | 103 | see [Tern.js's def json format](http://ternjs.net/doc/manual.html#typedef) and [Tern.js's sample def files](https://github.com/marijnh/tern/tree/master/defs). 104 | #### -x, --extrafiles `` 105 | sample files for target js lib. help for ternjs type inference. 106 | 107 | ex. `-x "./path/to/extrafile1.js,./path/to/extrafile2.js"` 108 | #### -D, --debug 109 | debug output mode 110 | #### -A, --voidAsAny 111 | force output `void` to `any` 112 | #### -i, --interfaceSameNameVar 113 | export a namespace property same with a interface name 114 | #### -a, --annotateTypeInstance 115 | annotate interface's constructor type as return type instance 116 | #### -g, --globalObject [value] 117 | how to export objects that same name with JS Global Object; "remove" or "wrap" or "rename"; DEFAULT:"wrap" 118 | 119 | ```javascript 120 | //--globalObject "remove" 121 | // ※no output 122 | 123 | //--globalObject "wrap" 124 | declare namespace mylib{ 125 | interface Error{ 126 | //... 127 | } 128 | } 129 | 130 | //--globalObject "rename" 131 | interface Mylib$Error{ 132 | //... 133 | } 134 | ``` 135 | 136 | 137 | #### -N, --NodeJSModule 138 | nodejs module special replace 139 | #### -e, --export 140 | add export statement in a bottom of d.ts file 141 | #### -S, --exportStyle [value] 142 | if --outExport true, select export style "es6" or "legacy" 143 | 144 | ```javascript 145 | //--exportStyle "legacy" 146 | declare module 'mylib'{ 147 | export = mylib; //legacy ts module export 148 | } 149 | //--exportStyle "es6" 150 | declare module 'mylib'{ 151 | export defalut mylib; //es6 style module export 152 | } 153 | ``` 154 | 155 | #### -M, --exportModuleName [value] 156 | 157 | exporting module name. 158 | 159 | ex. "EXAMPLE"; usage `import example = require("EXAMPLE");` 160 | 161 | #### -l, --lib `` 162 | 163 | add referrece path d.ts files. 164 | 165 | ex. `--lib path/to/ex1.d.ts,path/to/ex2.d.ts` 166 | 167 | => 168 | 169 | ```javascript 170 | /// 171 | /// 172 | ``` 173 | 174 | 175 | ## Known Issues 176 | 177 | 1. JSDoc tag (`@param`, `@return`) duplication when it was already defined in the target JavaScript code. 178 | 2. When `-p node` (Ternjs's Nodejs plugin) option is ON, dtsmake sometimes outputs nothing. 179 | 3. Only support Tern.js server plugins in [here](https://github.com/marijnh/tern/tree/0.14.0/plugin). 180 | 181 | ## TODOs 182 | 183 | * Tern.js's server plugin without default support. 184 | * tern/condense cmd cannot load 3rd party plugins (ex. [tern-gulp](https://github.com/angelozerr/tern-gulp) ), so, replace or patches it. 185 | 186 | see [TODO.md](./TODO.md) 187 | 188 | ## Licence 189 | 190 | MIT 191 | 192 | ## Author 193 | 194 | ConquestArrow 195 | [Github](https://github.com/ConquestArrow/) | [Qiita](http://qiita.com/ConquestArrow) 196 | 197 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | ### TODOs 2 | | Filename | line # | TODO 3 | |:------|:------:|:------ 4 | | dtsmake.ts | 247 | add line feed option (LF/CR/CR-LF) 5 | | dtsmake.ts | 541 | real replace 6 | | dtsmake.ts | 673 | ref path !n or !ret to searching 7 | | dtsmake.ts | 709 | Array type replace 8 | | dtsmake.ts | 1002 | research ternjs def's `` mean & what to do 9 | | dtsmake.ts | 1064 | other terndef node 10 | | dtsmake.ts | 1085 | isInClassOrInterface == true, export namespace 11 | | dtsmake.ts | 1348 | support multi platform BR 12 | | dtsmake.ts | 1413 | return info 13 | | dtsmake.ts | 1462 | option class or interface (default) 14 | | dtsmake.ts | 1472 | overloads support 15 | | dtsmake.ts | 1686 | check real path 16 | | dtsmake.ts | 1696 | check path exist 17 | | dtsmake.ts | 1728 | replace 18 | | dtsmake.ts | 1751 | generate class/interface 19 | | dtsmake.ts | 1758 | replace 20 | | dtsmake.ts | 1762 | replace 21 | | dtsmake.ts | 1856 | use namespace keyword option 22 | | dtsmake.ts | 4495 | compat to TypeScript AST -------------------------------------------------------------------------------- /bin/dtsmake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require("../lib/index"); -------------------------------------------------------------------------------- /example/dist/clone.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for clone 2 | // Project: [LIBRARY_URL_HERE] 3 | // Definitions by: [YOUR_NAME_HERE] <[YOUR_URL_HERE]> 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /** 7 | * Clones (copies) an Object using deep copying. 8 | * 9 | * This function supports circular references by default, but if you are certain 10 | * there are no circular references in your object, you can save some CPU time 11 | * by calling clone(obj, false). 12 | * 13 | * Caution: if `circular` is false and `parent` contains circular references, 14 | * your program may enter an infinite loop and crash. 15 | * 16 | * @param `parent` - the object to be cloned 17 | * @param `circular` - set to true if the object to be cloned may contain 18 | * circular references. (optional - true by default) 19 | * @param `depth` - set to a number if the object is only to be cloned to 20 | * a particular depth. (optional - defaults to Infinity) 21 | * @param `prototype` - sets the prototype to be used when cloning an object. 22 | * (optional - defaults to parent prototype). 23 | * @param `includeNonEnumerable` - set to true if the non-enumerable properties 24 | * should be cloned as well. Non-enumerable properties on the prototype 25 | * chain will be ignored. (optional - false by default) 26 | * @param parent 27 | * @param circular 28 | * @param depth 29 | * @param prototype 30 | * @param includeNonEnumerable 31 | * @return 32 | */ 33 | declare function clone(parent : any, circular : boolean, depth : number, prototype : any, includeNonEnumerable : any): any; 34 | 35 | /** 36 | * 37 | */ 38 | declare namespace clone{ 39 | 40 | /** 41 | * Simple flat clone using prototype, accepts only objects, usefull for property 42 | * override on FLAT configuration object (no nested props). 43 | * 44 | * USE WITH CAUTION! This may not behave as you wish if you do not know how this 45 | * works. 46 | * @param parent 47 | */ 48 | function clonePrototype(parent : any): void; 49 | 50 | /** 51 | * private utility functions 52 | * @param o 53 | * @return 54 | */ 55 | function __objToStr(o : any): string; 56 | 57 | /** 58 | * 59 | * @param o 60 | * @return 61 | */ 62 | function __isDate(o : any): boolean; 63 | 64 | /** 65 | * 66 | * @param o 67 | * @return 68 | */ 69 | function __isArray(o : any): boolean; 70 | 71 | /** 72 | * 73 | * @param o 74 | * @return 75 | */ 76 | function __isRegExp(o : any): boolean; 77 | 78 | /** 79 | * 80 | * @param re 81 | * @return 82 | */ 83 | function __getRegExpFlags(re : any): string; 84 | } 85 | -------------------------------------------------------------------------------- /example/dist/deeplib.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for deeplib 2 | // Project: [LIBRARY_URL_HERE] 3 | // Definitions by: [YOUR_NAME_HERE] <[YOUR_URL_HERE]> 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /** 7 | * 8 | */ 9 | declare namespace deep{ 10 | 11 | /** 12 | * 13 | */ 14 | namespace lib{ 15 | 16 | /** 17 | * 18 | * @return 19 | */ 20 | function sampleFunc(): boolean; 21 | 22 | /** 23 | * 24 | */ 25 | namespace sample{ 26 | 27 | /** 28 | * 29 | */ 30 | export var NUMBER : number; 31 | 32 | /** 33 | * 34 | */ 35 | interface Sample { 36 | 37 | /** 38 | * 39 | * @param a 40 | * @param b 41 | * @return 42 | */ 43 | new (a : any, b : any): Sample; 44 | } 45 | 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/dist/gulp-concat.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for gulpConcat 2 | // Project: [LIBRARY_URL_HERE] 3 | // Definitions by: [YOUR_NAME_HERE] <[YOUR_URL_HERE]> 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | /// 6 | 7 | /** 8 | * file can be a vinyl file object or a string 9 | * when a string it will construct a new one 10 | * @param file 11 | * @param opt 12 | * @return 13 | */ 14 | declare function gulpConcat(file : any, opt : any): any; 15 | /** 16 | * file can be a vinyl file object or a string 17 | * when a string it will construct a new one 18 | * @param override 19 | * @return 20 | */ 21 | declare function gulpConcat(override : any): any; 22 | 23 | declare module 'gulp-concat' { 24 | 25 | export = gulpConcat; //legacy ts module export 26 | } 27 | -------------------------------------------------------------------------------- /example/dist/gulp-header.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for gulpHeader 2 | // Project: [LIBRARY_URL_HERE] 3 | // Definitions by: [YOUR_NAME_HERE] <[YOUR_URL_HERE]> 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | /// 6 | 7 | /** 8 | * gulp-header plugin 9 | * @param headerText 10 | * @param data 11 | * @return 12 | */ 13 | declare function gulpHeader(headerText : any, data : any): any; 14 | /** 15 | * gulp-header plugin 16 | * @param override 17 | * @return 18 | */ 19 | declare function gulpHeader(override : any): any; 20 | 21 | declare module 'gulp-header' { 22 | 23 | export = gulpHeader; //legacy ts module export 24 | } 25 | -------------------------------------------------------------------------------- /example/dist/mylib.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for mylib 2 | // Project: [LIBRARY_URL_HERE] 3 | // Definitions by: [YOUR_NAME_HERE] <[YOUR_URL_HERE]> 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /** 7 | * 8 | */ 9 | declare namespace mylib{ 10 | 11 | /** 12 | * function prop test doc 13 | * @example not supported doc tag sample. 14 | * @param a param 1. may be number. 15 | * @param b param 2. may be number. 16 | * @return may be number. 17 | * @param a 18 | * @param b 19 | * @return 20 | */ 21 | function func(a : any, b : any): number; 22 | 23 | /** 24 | * string prop test doc 25 | */ 26 | export var str : string; 27 | 28 | /** 29 | * number prop test doc 30 | */ 31 | export var num : number; 32 | 33 | /** 34 | * boolean prop test doc 35 | */ 36 | export var bool : boolean; 37 | 38 | /** 39 | * array[string] prop test doc 40 | */ 41 | export var arr : Array; 42 | 43 | /** 44 | * added prop doc 45 | * @param a 46 | * @param b 47 | * @param c 48 | * @return 49 | */ 50 | function addedProp(a : string, b : any, c : number): string; 51 | } 52 | 53 | declare module 'mylib' { 54 | 55 | export = mylib; //legacy ts module export 56 | } 57 | -------------------------------------------------------------------------------- /example/dist/tern.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for tern 2 | // Project: [LIBRARY_URL_HERE] 3 | // Definitions by: [YOUR_NAME_HERE] <[YOUR_URL_HERE]> 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | //nodejs module namespace 6 | declare namespace tern{ 7 | 8 | /** 9 | * 10 | * @param name 11 | * @param init 12 | */ 13 | function registerPlugin(name : any, init : any): void; 14 | 15 | /** 16 | * 17 | */ 18 | namespace defaultOptions{ 19 | 20 | /** 21 | * 22 | */ 23 | var debug : boolean; 24 | 25 | /** 26 | * 27 | */ 28 | var async : boolean; 29 | 30 | /** 31 | * 32 | * @param _f 33 | * @param c 34 | */ 35 | function getFile(_f : any, c : any): void; 36 | 37 | /** 38 | * 39 | * @param name 40 | * @return 41 | */ 42 | function normalizeFilename(name : any): any; 43 | 44 | /** 45 | * 46 | */ 47 | var defs : Array; 48 | 49 | /** 50 | * 51 | */ 52 | var fetchTimeout : number; 53 | 54 | /** 55 | * 56 | */ 57 | var dependencyBudget : number; 58 | 59 | /** 60 | * 61 | */ 62 | var reuseInstances : boolean; 63 | 64 | /** 65 | * 66 | */ 67 | var stripCRs : boolean; 68 | 69 | /** 70 | * 71 | */ 72 | var ecmaVersion : number; 73 | 74 | /** 75 | * 76 | */ 77 | var projectDir : string; 78 | } 79 | 80 | /** 81 | * 82 | * @param name 83 | * @param desc 84 | */ 85 | function defineQueryType(name : any, desc : any): void; 86 | 87 | /** 88 | * 89 | */ 90 | interface Server { 91 | 92 | /** 93 | * 94 | * @param options 95 | */ 96 | new (options : /* !modules.``/node_modules/tern/lib/tern`js.Server.!0 */ any); 97 | 98 | /** 99 | * 100 | * @param name 101 | * @param text 102 | * @param parent 103 | */ 104 | addFile(name : any, text : any, parent : any): void; 105 | 106 | /** 107 | * 108 | * @param name 109 | */ 110 | delFile(name : any): void; 111 | 112 | /** 113 | * 114 | */ 115 | reset(): void; 116 | 117 | /** 118 | * 119 | */ 120 | cx : /*no type*/{}; 121 | 122 | /** 123 | * 124 | */ 125 | uses : number; 126 | 127 | /** 128 | * 129 | */ 130 | budgets : { 131 | } 132 | 133 | /** 134 | * 135 | * @param doc 136 | * @param c 137 | */ 138 | request(doc : any, c : any): void; 139 | 140 | /** 141 | * 142 | * @param name 143 | * @return 144 | */ 145 | findFile(name : string): /* !this.fileMap. */ any; 146 | 147 | /** 148 | * 149 | * @param c 150 | */ 151 | flush(c : any): void; 152 | 153 | /** 154 | * 155 | */ 156 | startAsyncAction(): void; 157 | 158 | /** 159 | * 160 | * @param err 161 | */ 162 | finishAsyncAction(err : any): void; 163 | 164 | /** 165 | * 166 | * @param defs 167 | * @param toFront 168 | */ 169 | addDefs(defs : any, toFront : any): void; 170 | 171 | /** 172 | * 173 | * @param name 174 | */ 175 | deleteDefs(name : any): void; 176 | 177 | /** 178 | * 179 | * @param name 180 | * @param options 181 | */ 182 | loadPlugin(name : any, options : boolean): void; 183 | 184 | /** 185 | * 186 | * @param name 187 | */ 188 | normalizeFilename(name : string): void; 189 | } 190 | 191 | /** 192 | * 193 | * @param file 194 | * @param pos 195 | * @param tolerant 196 | * @return 197 | */ 198 | function resolvePos(file : tern.ResolvePos0, pos : {} | number, tolerant : boolean): {} | number; 199 | 200 | /** 201 | * 202 | * @param query 203 | * @param file 204 | * @param pos 205 | * @return 206 | */ 207 | function outputPos(query : any, file : tern.OutputPos1, pos : any): tern.OutputPosRet; 208 | 209 | /** 210 | * 211 | * @param query 212 | * @param completions 213 | * @param name 214 | * @param aval 215 | * @param depth 216 | * @return 217 | */ 218 | function addCompletion(query : any, completions : tern.AddCompletion1, name : boolean | string, aval : any, depth : number): boolean | string; 219 | 220 | /** 221 | * 222 | * @param file 223 | * @param query 224 | * @param wide 225 | * @return 226 | */ 227 | function findQueryExpr(file : any, query : any, wide : boolean): tern.FindQueryExprRet; 228 | 229 | /** 230 | * 231 | * @param obj 232 | * @return 233 | */ 234 | function getSpan(obj : any): tern.GetSpanRet; 235 | 236 | /** 237 | * 238 | * @param srv 239 | * @param query 240 | * @param span 241 | * @param target 242 | */ 243 | function storeSpan(srv : any, query : any, span : any, target : tern.StoreSpan3): void; 244 | 245 | /** 246 | * 247 | */ 248 | var version : string; 249 | 250 | /** 251 | * 252 | */ 253 | var projectDir : string; 254 | 255 | /** 256 | * 257 | */ 258 | var files : Array; 259 | 260 | /** 261 | * 262 | */ 263 | var needsPurge : Array; 264 | 265 | /** 266 | * 267 | */ 268 | var uses : number; 269 | 270 | /** 271 | * 272 | */ 273 | var pending : number; 274 | 275 | /** 276 | * 277 | */ 278 | namespace plugins{ 279 | } 280 | } 281 | declare namespace tern{ 282 | // !modules.``/node_modules/tern/lib/tern`js.Server.!0 283 | 284 | /** 285 | * 286 | */ 287 | interface Server0 { 288 | } 289 | } 290 | declare namespace tern{ 291 | // !modules.``/node_modules/tern/lib/tern`js.resolvePos.!0 292 | 293 | /** 294 | * 295 | */ 296 | interface ResolvePos0 { 297 | 298 | /** 299 | * 300 | */ 301 | lineOffsets : Array; 302 | } 303 | } 304 | declare namespace tern{ 305 | // !modules.``/node_modules/tern/lib/tern`js.outputPos.!1 306 | 307 | /** 308 | * 309 | */ 310 | interface OutputPos1 { 311 | 312 | /** 313 | * 314 | */ 315 | lineOffsets : Array; 316 | 317 | /** 318 | * 319 | */ 320 | ast : /*no type*/{}; 321 | 322 | /** 323 | * 324 | */ 325 | text : string; 326 | } 327 | } 328 | declare namespace tern{ 329 | // !modules.``/node_modules/tern/lib/tern`js.outputPos.!ret 330 | 331 | /** 332 | * 333 | */ 334 | interface OutputPosRet { 335 | 336 | /** 337 | * 338 | */ 339 | line : number; 340 | 341 | /** 342 | * 343 | */ 344 | ch : number; 345 | } 346 | } 347 | declare namespace tern{ 348 | // !modules.``/node_modules/tern/lib/tern`js.addCompletion.!1 349 | type AddCompletion1 = Array; 350 | } 351 | declare namespace tern{ 352 | // !modules.``/node_modules/tern/lib/tern`js.findQueryExpr.!ret 353 | 354 | /** 355 | * 356 | */ 357 | interface FindQueryExprRet { 358 | 359 | /** 360 | * 361 | */ 362 | node : { 363 | 364 | /** 365 | * 366 | */ 367 | type : string; 368 | } 369 | } 370 | } 371 | declare namespace tern{ 372 | // !modules.``/node_modules/tern/lib/tern`js.getSpan.!ret 373 | 374 | /** 375 | * 376 | */ 377 | interface GetSpanRet { 378 | } 379 | } 380 | declare namespace tern{ 381 | // !modules.``/node_modules/tern/lib/tern`js.storeSpan.!3 382 | 383 | /** 384 | * 385 | */ 386 | interface StoreSpan3 { 387 | 388 | /** 389 | * 390 | */ 391 | contextOffset : number; 392 | } 393 | } 394 | 395 | declare module 'tern/lib/tern' { 396 | 397 | export = tern; //legacy ts module export 398 | } 399 | -------------------------------------------------------------------------------- /example/example.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * exapmle tests 5 | */ 6 | var child_process = require("child_process"); 7 | 8 | function exTest( 9 | op 10 | ){ 11 | if(!op.src)throw Error(); 12 | 13 | var cmd = "node ./node_modules/dtsmake/bin/dtsmake"; 14 | cmd += " -s "+op.src; 15 | cmd += " --dist "+op.dist; 16 | cmd += op.plugin ? " -p "+op.plugin : ""; 17 | cmd += op.name ? " -n "+op.name : ""; 18 | cmd += op.isExport ? " -e " : ""; 19 | cmd += op.exportStyle ? " -S '"+op.exportStyle+"'" : ""; 20 | cmd += op.exportModuleName ? " -M '"+op.exportModuleName+"'" : ""; 21 | cmd += op.debug ? " -D " : ""; 22 | cmd += op.extrafiles ? " -x "+op.extrafiles : ""; 23 | cmd += op.NodeJSModule ? " -N " : ""; 24 | cmd += op.lib ? " -l "+op.lib : ""; 25 | 26 | child_process.exec( 27 | //cmd 28 | cmd, 29 | //callback 30 | function(e,s,se){ 31 | if(e || se){ 32 | if(e) console.log(e.message); 33 | if(se) console.log(se.toString()); 34 | throw Error("example test failed."); 35 | } 36 | else{ 37 | console.log("[dtsmake extest] "+op.dist+".d.ts file output complete.") 38 | child_process.exec( 39 | "tsc "+op.dist+".d.ts", 40 | function(e2,s2,se2){ 41 | if(e2) throw Error(e2.message); 42 | else if(se2) throw Error(se2.toString()); 43 | else{ 44 | console.log("[dtsmake extest] "+op.src+ " 's d.ts tsc check complete."); 45 | } 46 | } 47 | ); 48 | } 49 | } 50 | ); 51 | } 52 | 53 | /* 54 | * tests 55 | */ 56 | 57 | //simple 58 | exTest({ 59 | src:"./src/mylib.js", 60 | dist:"./dist/mylib", 61 | name:"mylib", 62 | isExport:true, 63 | exportStyle:"legacy", 64 | exportModuleName:"mylib" 65 | }); 66 | //tern.js 67 | exTest({ 68 | src:"../node_modules/tern/lib/tern.js", 69 | dist:"./dist/tern", 70 | name:"tern", 71 | //debug:true, 72 | plugin:"node,modules", 73 | isExport:true, 74 | exportStyle:"legacy", 75 | exportModuleName:"tern/lib/tern", 76 | NodeJSModule:true, 77 | extrafiles:"../node_modules/tern/plugin/angular.js,../node_modules/tern/plugin/commonjs.js,../node_modules/tern/plugin/complete_strings.js,../node_modules/tern/plugin/doc_comment.js,../node_modules/tern/plugin/es_modules.js,../node_modules/tern/plugin/modules.js,../node_modules/tern/plugin/node.js,../node_modules/tern/plugin/node_resolve.js,../node_modules/tern/plugin/requirejs.js,../node_modules/tern/bin/tern,../node_modules/tern/lib/condense.js" 78 | }); 79 | //sinon.js 80 | exTest({ 81 | src:"../node_modules/sinon/pkg/sinon.js", 82 | dist:"./dist/sinon", 83 | name:"sinon", 84 | debug:false, 85 | //plugin:"node", 86 | isExport:true, 87 | exportStyle:"legacy", 88 | exportModuleName:"sinon", 89 | //NodeJSModule:true, 90 | //extrafiles:"../node_modules/tern/plugin/angular.js,../node_modules/tern/plugin/component.js,../node_modules/tern/plugin/doc_comment.js,../node_modules/tern/plugin/node.js,../node_modules/tern/plugin/requirejs.js" 91 | }); 92 | //clone.js 93 | exTest({ 94 | src:"../node_modules/clone/clone.js", 95 | dist:"./dist/clone", 96 | name:"clone", 97 | //plugin:"node", 98 | //isDebug:true, 99 | //isExport:true, 100 | //exportStyle:"legacy", 101 | //exportModuleName:"clone"//, 102 | //NodeJSModule:true, 103 | //extrafiles:"../node_modules/clone/test.js" 104 | }); 105 | //deep namespace lib 106 | exTest({ 107 | src:"./src/deeplib.js", 108 | dist:"./dist/deeplib", 109 | name:"deeplib", 110 | isDebug:true 111 | }); 112 | //gulp-header.js; gulp plugin sample 113 | exTest({ 114 | src:"../node_modules/gulp-header/index.js", 115 | dist:"./dist/gulp-header", 116 | name:"gulpHeader", 117 | plugin:"node", 118 | //isDebug:true, 119 | isExport:true, 120 | //exportStyle:"legacy", 121 | exportModuleName:"gulp-header", 122 | NodeJSModule:true, 123 | lib:"../test/fixture/node.d.ts" 124 | //extrafiles:"../node_modules/gulp-header/test/main.js" 125 | }); 126 | //gulp-concat.js; gulp plugin sample 127 | exTest({ 128 | src:"../node_modules/gulp-concat/index.js", 129 | dist:"./dist/gulp-concat", 130 | name:"gulpConcat", 131 | plugin:"node", 132 | //isDebug:true, 133 | isExport:true, 134 | //exportStyle:"legacy", 135 | exportModuleName:"gulp-concat", 136 | NodeJSModule:true, 137 | lib:"../test/fixture/node.d.ts", 138 | def:"../example/test/fixture/gulp.def.json", 139 | extrafiles:"../example/test/fixture/gulp-concat-sample.js" 140 | }); -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-test-dtsmake", 3 | "version": "0.0.0", 4 | "description": "example test for dtsmake", 5 | "main": "example.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "ConquestArrow", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "dtsmake": "file:.." 13 | }, 14 | "private": true 15 | } 16 | -------------------------------------------------------------------------------- /example/src/deeplib.js: -------------------------------------------------------------------------------- 1 | var deep; 2 | (function (deep) { 3 | var lib; 4 | (function (lib) { 5 | var sample; 6 | (function (sample) { 7 | sample.NUMBER = 0; 8 | var Sample = (function () { 9 | function Sample(a, b) { 10 | } 11 | return Sample; 12 | })(); 13 | sample.Sample = Sample; 14 | })(sample = lib.sample || (lib.sample = {})); 15 | })(lib = deep.lib || (deep.lib = {})); 16 | })(deep || (deep = {})); 17 | var deep; 18 | (function (deep) { 19 | var lib; 20 | (function (lib) { 21 | function sampleFunc() { 22 | return true; 23 | } 24 | lib.sampleFunc = sampleFunc; 25 | })(lib = deep.lib || (deep.lib = {})); 26 | })(deep || (deep = {})); 27 | -------------------------------------------------------------------------------- /example/src/mylib.js: -------------------------------------------------------------------------------- 1 | var mylib = { 2 | 3 | /** 4 | * function prop test doc 5 | * @example not supported doc tag sample. 6 | * @param a param 1. may be number. 7 | * @param b param 2. may be number. 8 | * @return may be number. 9 | */ 10 | func: function(a, b){ 11 | return a * b; 12 | }, 13 | 14 | /** 15 | * string prop test doc 16 | */ 17 | str: "string", 18 | /** 19 | * number prop test doc 20 | */ 21 | num: 1, 22 | /** 23 | * boolean prop test doc 24 | */ 25 | bool: false, 26 | /** 27 | * array[string] prop test doc 28 | */ 29 | arr: [ 30 | "a", 31 | "b", 32 | "c" 33 | ] 34 | 35 | 36 | 37 | }; 38 | 39 | /** 40 | * added prop doc 41 | */ 42 | mylib.addedProp = function(a, b, c){ 43 | if(!a) a = "hoge"; 44 | if(!c) c = 0; 45 | 46 | return a + (b * c); 47 | }; -------------------------------------------------------------------------------- /example/test/fixture/gulp-concat-sample.js: -------------------------------------------------------------------------------- 1 | //from gulp-concat README.md 2 | 3 | /* 4 | This will concat files by your operating systems newLine. It will take the base directory from the first file that passes through it. 5 | */ 6 | var gulp = require("gulp"); 7 | var concat = require('gulp-concat'); 8 | 9 | gulp.task('scripts', function() { 10 | return gulp.src('./lib/*.js') 11 | .pipe(concat('all.js')) 12 | .pipe(gulp.dest('./dist/')); 13 | }); 14 | 15 | /* 16 | Files will be concatenated in the order that they are specified in the gulp.src function. For example, to concat ./lib/file3.js, ./lib/file1.js and ./lib/file2.js in that order, the following code will create a task to do that: 17 | */ 18 | gulp.task('scripts2', function() { 19 | return gulp.src(['./lib/file3.js', './lib/file1.js', './lib/file2.js']) 20 | .pipe(concat('all.js')) 21 | .pipe(gulp.dest('./dist/')); 22 | }); 23 | 24 | /* 25 | To specify cwd, path and other vinyl properties, gulp-concat accepts Object as first argument: 26 | */ 27 | gulp.task('scripts3', function() { 28 | return gulp.src(['./lib/file3.js', './lib/file1.js', './lib/file2.js']) 29 | .pipe(concat({ path: 'new.js', stat: { mode: 0666 }})) 30 | .pipe(gulp.dest('./dist')); 31 | }); 32 | -------------------------------------------------------------------------------- /example/test/mylib-test.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import mylib = require("mylib"); 3 | var s = mylib.addedProp("mylib", true, 9); -------------------------------------------------------------------------------- /example/test/tern-test.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import tern = require("tern/lib/tern"); -------------------------------------------------------------------------------- /gulpfile.ts: -------------------------------------------------------------------------------- 1 | import gulp = require("gulp"); 2 | import gts = require("gulp-typescript"); 3 | import concat = require("gulp-concat"); 4 | //var sq = require("streamqueue"); 5 | //import header from 'gulp-header'//= require('gulp-header'); 6 | const todo = require('gulp-todo'); 7 | 8 | require('gulp-release-tasks')(gulp); 9 | 10 | /* 11 | gulp.task("cmdbuild", ()=>{ 12 | let result = gulp 13 | .src(["./src/index.ts"]) 14 | .pipe( 15 | gts( 16 | { 17 | noImplicitAny:true, 18 | suppressImplicitAnyIndexErrors: true, 19 | module:"commonjs", 20 | target:"ES5", 21 | //noEmitOnError:true, 22 | //out:"./lib/index.js" 23 | }, 24 | undefined, 25 | gts.reporter.fullReporter() 26 | ) 27 | ); 28 | return result 29 | .js 30 | .pipe(gulp.dest("./lib/")) 31 | .pipe(header("#!/usr/bin/env node\n")) 32 | .pipe(concat("dtsgen")) 33 | .pipe(gulp.dest("./bin/")); 34 | });*/ 35 | 36 | gulp.task("build", ()=>{ 37 | let tsProj = gts.createProject("tsconfig.json") 38 | //tsProj.src("./node_modules/@types") 39 | 40 | let result = gulp 41 | .src("./src/*.ts") 42 | .pipe(tsProj()); 43 | 44 | return result 45 | .js 46 | .pipe(gulp.dest("./lib/")); 47 | }); 48 | 49 | gulp.task("todo",()=>{ 50 | return gulp 51 | .src("./src/*.ts") 52 | .pipe(todo({ 53 | fileName:"TODO.md" 54 | })) 55 | .pipe(gulp.dest('./')); 56 | }) 57 | 58 | gulp.task("watch",()=>{ 59 | gulp.watch("./src/*.ts", ["build"]); 60 | gulp.watch("./src/*.ts", ["todo"]); 61 | }) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dtsmake", 3 | "version": "0.0.10", 4 | "description": "TypeScript d.ts file generator from JavaScript files", 5 | "main": "lib/dtsmake.js", 6 | "bin": "bin/dtsmake", 7 | "scripts": { 8 | "test": "mocha --compilers ts:ts-node/register test/*.ts", 9 | "testw": "mocha --compilers ts:ts-node/register test/*.ts -w", 10 | "extest": "(cd example && npm install --save-dev ../ && node example.js)", 11 | "build": "tsc" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/ConquestArrow/dtsmake/" 16 | }, 17 | "bugs": { 18 | "url": "https://github.com/ConquestArrow/dtsmake/issues" 19 | }, 20 | "engines": { 21 | "npm": "2.x.x - 3.x.x" 22 | }, 23 | "keywords": [ 24 | "TypeScript", 25 | "JavaScript", 26 | "generator" 27 | ], 28 | "author": "ConquestArrow", 29 | "license": "MIT", 30 | "private": false, 31 | "devDependencies": { 32 | "@types/clone": "^0.1.30", 33 | "@types/commander": "^2.3.31", 34 | "@types/empower": "^1.2.30", 35 | "@types/gulp": "^3.8.32", 36 | "@types/gulp-concat": "0.0.29", 37 | "@types/gulp-typescript": "0.0.32", 38 | "@types/mocha": "^2.2.33", 39 | "@types/node": "^7.0.5", 40 | "@types/power-assert": "^1.4.29", 41 | "@types/power-assert-formatter": "^1.4.28", 42 | "@types/sinon": "^1.16.33", 43 | "espower-typescript": "^7.0.0", 44 | "gulp": "^3.9.1", 45 | "gulp-concat": "^2.6.0", 46 | "gulp-header": "^1.8.7", 47 | "gulp-release-tasks": "0.0.3", 48 | "gulp-todo": "^5.2.0", 49 | "gulp-typescript": "^3.1.3", 50 | "mocha": "^2.5.3", 51 | "power-assert": "^1.4.1", 52 | "sinon": "^1.17.4", 53 | "ts-node": "^2.0.0", 54 | "typescript": "^2.1.4", 55 | "typescript-node": "^0.1.3", 56 | "typescript-register": "^1.1.0", 57 | "typescript-require": "^0.2.9-1" 58 | }, 59 | "dependencies": { 60 | "clone": "^2.1.0", 61 | "commander": "^2.9.0", 62 | "tern": "^0.21.0" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /sample/infer.js.json: -------------------------------------------------------------------------------- 1 | { 2 | "!name": "node_modules/tern/lib/infer.js", 3 | "!define": { 4 | "tern.toString.!2": "+tern.Arr", 5 | "tern.simplifyTypes.!ret": "[?]", 6 | "tern.constraint.!0": { 7 | "construct": "fn(inner: ?, weight: ?)", 8 | "addType": "fn(tp: ?, weight: ?)", 9 | "propagatesTo": "fn()", 10 | "typeHint": "fn()", 11 | "propHint": "fn()" 12 | }, 13 | "tern.constraint.!ret": "fn()", 14 | "tern.getInstance.!1": "+tern.TimedOut", 15 | "tern.Fn.prototype.getFunctionType.!ret": "+tern.Fn", 16 | "tern.withContext.!1": "fn()", 17 | "tern.findExpressionAt.!4": "fn(_t: ?, node: ?) -> bool", 18 | "tern.findExpressionAround.!4": "fn(_t: ?, node: ?) -> bool", 19 | "tern.expressionType.!0": {}, 20 | "tern.forAllPropertiesOf.!0": { 21 | "toString": "fn(maxDepth: number) -> !this.name", 22 | "hasProp": "fn(prop: ?, searchProto: ?)", 23 | "defProp": "fn(prop: ?, originNode: ?) -> !this.maybeProps", 24 | "getProp": "fn(prop: ?) -> !this.maybeProps", 25 | "broadcastProp": "fn(prop: ?, val: ?, local: ?)", 26 | "onProtoProp": "fn(prop: ?, val: ?, _local: ?)", 27 | "ensureMaybeProps": "fn() -> !this.maybeProps", 28 | "removeProp": "fn(prop: ?)", 29 | "forAllProps": "fn(c: ?)", 30 | "maybeUnregProtoPropHandler": "fn()", 31 | "unregPropHandler": "fn(handler: ?)", 32 | "gatherProperties": "fn(f: ?, depth: ?)", 33 | "getObjType": "fn() -> !this", 34 | "constructor": "tern.Obj" 35 | }, 36 | "tern.Obj.instances.": { 37 | "instance": "+tern.Obj" 38 | } 39 | }, 40 | "tern": { 41 | "toString": "fn(type: ?, maxDepth: number, parent: +tern.Fn|+tern.Arr) -> string", 42 | "AVal": { 43 | "prototype": { 44 | "purge": "fn(test: ?)" 45 | }, 46 | "!type": "fn()", 47 | "types": "[?]", 48 | "maxWeight": "number" 49 | }, 50 | "simplifyTypes": "fn(types: ?) -> [!0.]", 51 | "constraint": { 52 | "!type": "fn(methods: tern.constraint.!0|?) -> fn()", 53 | "!doc": "PROPAGATION STRATEGIES" 54 | }, 55 | "PropHasSubset": "fn()", 56 | "IsCallee": "fn()", 57 | "IsCtor": "fn()", 58 | "getInstance": "fn(obj: +tern.Obj, ctor: ?) -> +tern.Obj", 59 | "IsProto": "fn()", 60 | "IfObj": "fn()", 61 | "Type": { 62 | "!type": "fn()", 63 | "!doc": "TYPE OBJECTS" 64 | }, 65 | "Prim": "fn(proto: ?, name: string)", 66 | "Obj": { 67 | "prototype": { 68 | "purge": "fn(test: ?) -> bool" 69 | }, 70 | "!type": "fn(proto: bool, name: string)", 71 | "name": "string", 72 | "instances": "[tern.Obj.instances.]" 73 | }, 74 | "Fn": { 75 | "prototype": { 76 | "toString": "fn(maxDepth: number) -> string", 77 | "getProp": "fn(prop: ?)", 78 | "defProp": "fn(prop: ?, originNode: ?)", 79 | "getFunctionType": "fn() -> !this", 80 | "purge": "fn(test: ?)", 81 | "!proto": "tern.Obj.prototype", 82 | "constructor": "tern.Fn" 83 | }, 84 | "!type": "fn(name: string, self: +tern.AVal, args: [?], argNames: [string], retval: ?)", 85 | "self": "+tern.AVal", 86 | "args": "[?]", 87 | "argNames": "[string]", 88 | "proto": "bool", 89 | "name": "string" 90 | }, 91 | "Arr": { 92 | "prototype": { 93 | "toString": "fn(maxDepth: number) -> string", 94 | "!proto": "tern.Obj.prototype", 95 | "constructor": "tern.Arr" 96 | }, 97 | "!type": "fn(contentType: +tern.AVal)", 98 | "proto": "bool", 99 | "name": "string" 100 | }, 101 | "Context": { 102 | "!type": "fn(defs: ?, parent: ?)", 103 | "!doc": "INFERENCE CONTEXT" 104 | }, 105 | "cx": "fn()", 106 | "withContext": "fn(context: ?, f: fn())", 107 | "TimedOut": { 108 | "prototype": { 109 | "name": "string", 110 | "!proto": "Error.prototype" 111 | }, 112 | "!type": "fn()", 113 | "message": "string" 114 | }, 115 | "withTimeout": "fn(ms: ?, f: ?)", 116 | "addOrigin": "fn(origin: string)", 117 | "Scope": { 118 | "prototype": { 119 | "defVar": "fn(name: ?, originNode: ?)", 120 | "!proto": "tern.Obj.prototype", 121 | "constructor": "tern.Scope" 122 | }, 123 | "!type": "fn(prev: ?)", 124 | "!doc": "SCOPES" 125 | }, 126 | "parse": "fn(text: ?, passes: ?, options: ?)", 127 | "analyze": { 128 | "!type": "fn(ast: ?, name: string, scope: ?, passes: ?)", 129 | "!doc": "ANALYSIS INTERFACE" 130 | }, 131 | "purge": { 132 | "!type": "fn(origins: ?, start: ?, end: ?)", 133 | "!doc": "PURGING" 134 | }, 135 | "findExpressionAt": "fn(ast: ?, start: ?, end: ?, defaultScope: ?, filter: ?)", 136 | "findExpressionAround": "fn(ast: ?, start: ?, end: ?, defaultScope: ?, filter: ?)", 137 | "expressionType": "fn(found: tern.expressionType.!0)", 138 | "parentNode": { 139 | "!type": "fn(child: ?, ast: ?)", 140 | "!doc": "Finding the expected type of something, from context" 141 | }, 142 | "typeFromContext": "fn(ast: ?, found: tern.expressionType.!0)", 143 | "resetGuessing": "fn(val: ?)", 144 | "didGuess": "fn() -> bool", 145 | "forAllPropertiesOf": "fn(type: ?, f: ?)", 146 | "findRefs": "fn(ast: ?, baseScope: ?, name: ?, refScope: ?, f: ?)", 147 | "findPropRefs": "fn(ast: ?, scope: ?, objType: ?, propName: ?, f: ?)", 148 | "scopeAt": { 149 | "!type": "fn(ast: ?, pos: ?, defaultScope: ?) -> !2", 150 | "!doc": "LOCAL-VARIABLE QUERIES" 151 | }, 152 | "forAllLocalsAt": "fn(ast: ?, pos: ?, defaultScope: ?, f: ?)" 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /sample/sample.json: -------------------------------------------------------------------------------- 1 | {"!name":"node_modules/tern/lib/infer.js","!define":{"tern.toString.!2":[{"type":7,"class":"+tern.Arr"}],"tern.simplifyTypes.!ret":[{"type":6,"arrayType":[{"type":0}]}],"tern.constraint.!0":{"construct":[{"type":5,"ret":[{"type":1}],"params":[{"name":"inner","type":0},{"name":"weight","type":0}]}],"addType":[{"type":5,"ret":[{"type":1}],"params":[{"name":"tp","type":0},{"name":"weight","type":0}]}],"propagatesTo":[{"type":5,"ret":[{"type":1}],"params":null}],"typeHint":[{"type":5,"ret":[{"type":1}],"params":null}],"propHint":[{"type":5,"ret":[{"type":1}],"params":null}],"!!!dtsinterface!!!":"Constraint0","!!!dtsnamespace!!!":"tern"},"tern.constraint.!ret":[{"type":5,"ret":[{"type":1}],"params":null}],"tern.getInstance.!1":[{"type":7,"class":"+tern.TimedOut"}],"tern.Fn.prototype.getFunctionType.!ret":[{"type":7,"class":"+tern.Fn"}],"tern.withContext.!1":[{"type":5,"ret":[{"type":1}],"params":null}],"tern.findExpressionAt.!4":[{"type":5,"ret":[{"type":2}],"params":[{"name":"_t","type":0},{"name":"node","type":0}]}],"tern.findExpressionAround.!4":[{"type":5,"ret":[{"type":2}],"params":[{"name":"_t","type":0},{"name":"node","type":0}]}],"tern.expressionType.!0":{"!!!dtsinterface!!!":"ExpressionType0","!!!dtsnamespace!!!":"tern"},"tern.forAllPropertiesOf.!0":{"$toString":[{"type":5,"ret":[{"type":9,"class":"!this.name"}],"params":[{"name":"maxDepth","type":3}]}],"hasProp":[{"type":5,"ret":[{"type":1}],"params":[{"name":"prop","type":0},{"name":"searchProto","type":0}]}],"defProp":[{"type":5,"ret":[{"type":9,"class":"!this.maybeProps"}],"params":[{"name":"prop","type":0},{"name":"originNode","type":0}]}],"getProp":[{"type":5,"ret":[{"type":9,"class":"!this.maybeProps"}],"params":[{"name":"prop","type":0}]}],"broadcastProp":[{"type":5,"ret":[{"type":1}],"params":[{"name":"prop","type":0},{"name":"val","type":0},{"name":"local","type":0}]}],"onProtoProp":[{"type":5,"ret":[{"type":1}],"params":[{"name":"prop","type":0},{"name":"val","type":0},{"name":"_local","type":0}]}],"ensureMaybeProps":[{"type":5,"ret":[{"type":9,"class":"!this.maybeProps"}],"params":null}],"removeProp":[{"type":5,"ret":[{"type":1}],"params":[{"name":"prop","type":0}]}],"forAllProps":[{"type":5,"ret":[{"type":1}],"params":[{"name":"c","type":0}]}],"maybeUnregProtoPropHandler":[{"type":5,"ret":[{"type":1}],"params":null}],"unregPropHandler":[{"type":5,"ret":[{"type":1}],"params":[{"name":"handler","type":0}]}],"gatherProperties":[{"type":5,"ret":[{"type":1}],"params":[{"name":"f","type":0},{"name":"depth","type":0}]}],"getObjType":[{"type":5,"ret":[{"type":9,"class":"!this"}],"params":null}],"!!!dtsinterface!!!":"ForAllPropertiesOf0","!!!dtsnamespace!!!":"tern"},"tern.Obj.instances.":{"instance":[{"type":7,"class":"+tern.Obj"}],"!!!dtsinterface!!!":"InstancesI","!!!dtsnamespace!!!":"tern.Obj"}},"tern":{"$toString":[{"type":5,"ret":[{"type":4}],"params":[{"name":"type","type":0},{"name":"maxDepth","type":3},[{"type":7,"name":"parent","class":"+tern.Fn"},{"type":7,"name":"parent","class":"Arr"}]]}],"AVal":{"new ":[{"type":5,"name":"AVal","ret":[{"type":7,"class":"AVal"}],"params":null}],"purge":[{"type":5,"ret":[{"type":1}],"params":[{"name":"test","type":0}]}],"types":[{"type":6,"arrayType":[{"type":0}]}],"maxWeight":[{"type":3}]},"simplifyTypes":[{"type":5,"ret":[{"type":7,"arrayType":[{"type":9,"class":"!0."}],"class":"SimplifyTypesRet"}],"params":[{"name":"types","type":0}]}],"constraint":{"!type":[{"type":5,"ret":[{"type":7,"ret":[{"type":1}],"params":null,"class":"ConstraintRet"}],"params":[[{"type":7,"name":"methods","class":"Constraint0"},{"type":0,"name":"methods"}]]}],"!doc":"PROPAGATION STRATEGIES"},"PropHasSubset":[{"type":5,"ret":[{"type":1}],"params":null}],"IsCallee":[{"type":5,"ret":[{"type":1}],"params":null}],"IsCtor":[{"type":5,"ret":[{"type":1}],"params":null}],"getInstance":[{"type":5,"ret":[{"type":7,"class":"+tern.Obj"}],"params":[{"name":"obj","type":7,"class":"+tern.Obj"},{"name":"ctor","type":7,"class":"TimedOut"}]}],"IsProto":[{"type":5,"ret":[{"type":1}],"params":null}],"IfObj":[{"type":5,"ret":[{"type":1}],"params":null}],"Type":{"!type":[{"type":5,"ret":[{"type":1}],"params":null}],"!doc":"TYPE OBJECTS"},"Prim":[{"type":5,"ret":[{"type":1}],"params":[{"name":"proto","type":0},{"name":"name","type":4}]}],"Obj":{"new ":[{"type":5,"name":"Obj","ret":[{"type":7,"class":"Obj"}],"params":[{"name":"proto","type":2},{"name":"name","type":4}]}],"purge":[{"type":5,"ret":[{"type":2}],"params":[{"name":"test","type":0}]}],"name":[{"type":4}],"instances":[{"type":6,"arrayType":[{"type":7,"class":"tern.Obj.InstancesI"}]}]},"Fn":{"new ":[{"type":5,"name":"Fn","ret":[{"type":7,"class":"Fn"}],"params":[{"name":"name","type":4},{"name":"self","type":7,"class":"+tern.AVal"},{"type":6,"name":"args","arrayType":[{"type":0}]},{"type":6,"name":"argNames","arrayType":[{"type":4}]},{"name":"retval","type":0}]}],"getProp":[{"type":5,"ret":[{"type":1}],"params":[{"name":"prop","type":0}]}],"defProp":[{"type":5,"ret":[{"type":1}],"params":[{"name":"prop","type":0},{"name":"originNode","type":0}]}],"getFunctionType":[{"type":5,"ret":[{"type":7,"class":"Fn"}],"params":null}],"purge":[{"type":5,"ret":[{"type":1}],"params":[{"name":"test","type":0}]}],"!proto":[{"type":9,"class":"tern.Obj.prototype"}],"self":[{"type":7,"class":"+tern.AVal"}],"args":[{"type":6,"arrayType":[{"type":0}]}],"argNames":[{"type":6,"arrayType":[{"type":4}]}],"proto":[{"type":2}],"name":[{"type":4}]},"Arr":{"new ":[{"type":5,"name":"Arr","ret":[{"type":7,"class":"Arr"}],"params":[{"name":"contentType","type":7,"class":"+tern.AVal"}]}],"!proto":[{"type":9,"class":"tern.Obj.prototype"}],"proto":[{"type":2}],"name":[{"type":4}]},"Context":{"!type":[{"type":5,"ret":[{"type":1}],"params":[{"name":"defs","type":0},{"name":"parent","type":0}]}],"!doc":"INFERENCE CONTEXT"},"cx":[{"type":5,"ret":[{"type":1}],"params":null}],"withContext":[{"type":5,"ret":[{"type":1}],"params":[{"name":"context","type":0},{"name":"f","type":7,"class":"WithContext1"}]}],"TimedOut":{"new ":[{"type":5,"name":"TimedOut","ret":[{"type":7,"class":"TimedOut"}],"params":null}],"name":[{"type":4}],"!proto":[{"type":9,"class":"Error.prototype"}],"message":[{"type":4}]},"withTimeout":[{"type":5,"ret":[{"type":1}],"params":[{"name":"ms","type":0},{"name":"f","type":0}]}],"addOrigin":[{"type":5,"ret":[{"type":1}],"params":[{"name":"origin","type":4}]}],"Scope":{"new ":[{"type":5,"name":"Scope","ret":[{"type":7,"class":"Scope"}],"params":[{"name":"prev","type":0}]}],"defVar":[{"type":5,"ret":[{"type":1}],"params":[{"name":"name","type":0},{"name":"originNode","type":0}]}],"!proto":[{"type":9,"class":"tern.Obj.prototype"}],"!doc":"SCOPES"},"parse":[{"type":5,"ret":[{"type":1}],"params":[{"name":"text","type":0},{"name":"passes","type":0},{"name":"options","type":0}]}],"analyze":{"!type":[{"type":5,"ret":[{"type":1}],"params":[{"name":"ast","type":0},{"name":"name","type":4},{"name":"scope","type":0},{"name":"passes","type":0}]}],"!doc":"ANALYSIS INTERFACE"},"purge":{"!type":[{"type":5,"ret":[{"type":1}],"params":[{"name":"origins","type":0},{"name":"start","type":0},{"name":"end","type":0}]}],"!doc":"PURGING"},"findExpressionAt":[{"type":5,"ret":[{"type":1}],"params":[{"name":"ast","type":0},{"name":"start","type":0},{"name":"end","type":0},{"name":"defaultScope","type":0},{"name":"filter","type":7,"class":"FindExpressionAt4"}]}],"findExpressionAround":[{"type":5,"ret":[{"type":1}],"params":[{"name":"ast","type":0},{"name":"start","type":0},{"name":"end","type":0},{"name":"defaultScope","type":0},{"name":"filter","type":7,"class":"FindExpressionAround4"}]}],"expressionType":[{"type":5,"ret":[{"type":1}],"params":[{"name":"found","type":7,"class":"ExpressionType0"}]}],"parentNode":{"!type":[{"type":5,"ret":[{"type":1}],"params":[{"name":"child","type":0},{"name":"ast","type":0}]}],"!doc":"Finding the expected type of something, from context"},"typeFromContext":[{"type":5,"ret":[{"type":1}],"params":[{"name":"ast","type":0},{"name":"found","type":9,"class":"tern.expressionType.!0"}]}],"resetGuessing":[{"type":5,"ret":[{"type":1}],"params":[{"name":"val","type":0}]}],"didGuess":[{"type":5,"ret":[{"type":2}],"params":null}],"forAllPropertiesOf":[{"type":5,"ret":[{"type":1}],"params":[{"name":"type","type":7,"class":"ForAllPropertiesOf0"},{"name":"f","type":0}]}],"findRefs":[{"type":5,"ret":[{"type":1}],"params":[{"name":"ast","type":0},{"name":"baseScope","type":0},{"name":"name","type":0},{"name":"refScope","type":0},{"name":"f","type":0}]}],"findPropRefs":[{"type":5,"ret":[{"type":1}],"params":[{"name":"ast","type":0},{"name":"scope","type":0},{"name":"objType","type":0},{"name":"propName","type":0},{"name":"f","type":0}]}],"scopeAt":{"!type":[{"type":5,"ret":[{"type":9,"class":"!2"}],"params":[{"name":"ast","type":0},{"name":"pos","type":0},{"name":"defaultScope","type":0}]}],"!doc":"LOCAL-VARIABLE QUERIES"},"forAllLocalsAt":[{"type":5,"ret":[{"type":1}],"params":[{"name":"ast","type":0},{"name":"pos","type":0},{"name":"defaultScope","type":0},{"name":"f","type":0}]}]}} -------------------------------------------------------------------------------- /sample/tern.js.json: -------------------------------------------------------------------------------- 1 | { 2 | "!name": "tern", 3 | "!define": { 4 | "!node": { 5 | "node_modules/tern/lib/tern`js": { 6 | "registerPlugin": "fn(name: string, init: ?)", 7 | "defaultOptions": { 8 | "debug": "bool", 9 | "async": "bool", 10 | "getFile": "fn(_f: ?, c: ?)", 11 | "defs": "[?]", 12 | "fetchTimeout": "number", 13 | "dependencyBudget": "number", 14 | "reuseInstances": "bool", 15 | "stripCRs": "bool" 16 | }, 17 | "defineQueryType": "fn(name: string, desc: ?)", 18 | "Server": { 19 | "prototype": { 20 | "addFile": "fn(name: string, text: string, parent: ?)", 21 | "delFile": "fn(name: string)", 22 | "reset": "fn()", 23 | "request": "fn(doc: ?, c: fn(number, number) -> number|fn(err: string|?, data: ?))", 24 | "findFile": "fn(name: string) -> !this.fileMap.", 25 | "flush": "fn(c: fn())", 26 | "startAsyncAction": "fn()", 27 | "finishAsyncAction": "fn(err: ?)" 28 | }, 29 | "!type": "fn(options: ?)" 30 | }, 31 | "resolvePos": "fn(file: ?, pos: ?|number, tolerant: bool) -> !1", 32 | "outputPos": "fn(query: ?|?, file: ?, pos: ?) -> ?", 33 | "findQueryExpr": "fn(file: ?, query: ?, wide: bool) -> !node.node_modules/tern/lib/tern`js.findQueryExpr.!ret", 34 | "getSpan": "fn(obj: ?) -> ?", 35 | "storeSpan": "fn(srv: +!node.node_modules/tern/lib/tern`js.Server, query: ?|?, span: ?, target: ?)", 36 | "version": "string" 37 | } 38 | }, 39 | "!node.node_modules/tern/lib/tern`js.outputPos.!1": { 40 | "lineOffsets": "[number]", 41 | "text": "string", 42 | "scope": {} 43 | }, 44 | "!node.node_modules/tern/lib/tern`js.outputPos.!ret": { 45 | "line": "number", 46 | "ch": "number" 47 | }, 48 | "!node.node_modules/tern/lib/tern`js.findQueryExpr.!ret": { 49 | "node": { 50 | "type": "string" 51 | } 52 | }, 53 | "!node.node_modules/tern/lib/tern`js.getSpan.!ret": {}, 54 | "!node.node_modules/tern/lib/tern`js.storeSpan.!0": "+!node.node_modules/tern/lib/tern`js.Server" 55 | }, 56 | "tern": {} 57 | } 58 | -------------------------------------------------------------------------------- /src/dtsmake.ts: -------------------------------------------------------------------------------- 1 | import fs = require('fs'); 2 | import path = require('path'); 3 | import clone = require('clone'); 4 | 5 | export namespace dtsmake{ 6 | 7 | const DTS_INTERFACE_STR = "!!!dtsinterface!!!"; 8 | const DTS_NAMESPACE_STR = "!!!dtsnamespace!!!"; 9 | 10 | export class DTSMake{ 11 | /** 12 | * ternjs json format data 13 | */ 14 | ternjsData:JSON; 15 | 16 | /** 17 | * currently nodejs module internal name 18 | * ex. "node_modules/path/to/module`js" 19 | */ 20 | nodeModuleName:string; 21 | 22 | /** 23 | * user defined name when tern/condense 24 | */ 25 | userDefinedModuleName:string; 26 | 27 | /** 28 | * Default Options 29 | */ 30 | option:Option = { 31 | // debug mode 32 | isDebug:false, 33 | // force output "void" to "any" 34 | isOutVoidAsAny:false, 35 | // export a namespace property same with a interface 36 | isExportInterfaceSameNameVar:true, 37 | // annotate interface constructor type as return type instance 38 | isAnnotateTypeInstance:true, 39 | // node module special replace 40 | isNodeJsModule:false, 41 | // add export statement in a bottom of d.ts file 42 | isOutExport:true, 43 | // how to export objects that has same name with JS global object 44 | globalObject:Option.GlobalObject.WRAP, 45 | // if isOutExport true, select export style "es6" or "legacy" 46 | exportStyle:Option.ExportStyle.LEGACY, 47 | // exporting module name 48 | // ex. "EXAMPLE"; usage 'import example = require("EXAMPLE");' 49 | // ex. "EXAMPLE/lib"; usage 'import example = require("EXAMPLE/lib");' 50 | // check javascript lib's import style 51 | exportModuleName:"" 52 | }; 53 | 54 | /** 55 | * main function 56 | * load json file 57 | */ 58 | main( 59 | srcPathStr:string, 60 | distPathStr:string, 61 | options?:Option 62 | ):void; 63 | /** 64 | * 65 | */ 66 | main( 67 | srcString:string, 68 | distPathStr:string, 69 | options?:Option 70 | ):void; 71 | 72 | main( 73 | param1:string, 74 | distPathStr:string, 75 | options?:Option 76 | ){ 77 | this.overrideDefaultOptions(options); 78 | 79 | if(/\n/.test(param1)){ 80 | //source code text 81 | let s = this.parseTernJson(JSON.parse(param1), distPathStr); 82 | this.saveTSDFile(distPathStr,s); 83 | } 84 | else if(/\.json$/.test(param1)){ 85 | //src json path 86 | this.loadTernJson(param1, (data:JSON)=>{ 87 | let s = this.parseTernJson(data, distPathStr); 88 | 89 | this.saveTSDFile(distPathStr,s); 90 | }) 91 | } 92 | 93 | } 94 | 95 | 96 | private overrideDefaultOptions(options?:Option){ 97 | if(options){ 98 | for(let i in options){ 99 | if(this.option[i]!==undefined || this.option[i]!==null){ 100 | //override default options 101 | this.option[i] = options[i]; 102 | } 103 | } 104 | } 105 | } 106 | 107 | /** 108 | * load ternjs json format data 109 | * @param pathStr path/to/file/example.json, must be strings 110 | */ 111 | loadTernJson(pathStr:string, cb:(data:JSON)=>void){ 112 | fs.readFile(pathStr,"UTF-8", (err:NodeJS.ErrnoException, data:Buffer)=>{ 113 | if(err)throw Error(err.name+" "+err.code+" "+err.message+" "+err.path); 114 | 115 | this.ternjsData = JSON.parse(data.toString()); 116 | //console.log(JSON.stringify(this.ternjsData)); 117 | console.log("Load a JSON file complete."); 118 | //this.parseTernJson(this.ternjsData); 119 | cb(this.ternjsData); 120 | }); 121 | } 122 | 123 | /** 124 | * save typescript d.ts file. 125 | * TODO: add line feed option (LF/CR/CR-LF) 126 | * @param name path/to/filename, no need file ext. like ".d.ts" 127 | * @param src file data strings. 128 | */ 129 | saveTSDFile(name:string,src:string):boolean{ 130 | try{ 131 | fs.writeFile(`${name}.d.ts`, src, {encoding:"UTF-8"}, (err:NodeJS.ErrnoException)=>{ 132 | if(err)throw Error(err.name+" "+err.code+" "+err.message+" "+err.path); 133 | console.log(`File saved. (${name}.d.ts)`); 134 | 135 | }); 136 | }catch(e){ 137 | throw Error(e); 138 | //return false; 139 | } 140 | 141 | return true; 142 | } 143 | 144 | saveJSON(pathStr:string, data:string, complete:Function){ 145 | fs.writeFile(pathStr, data, {encoding:"UTF-8"}, (e:NodeJS.ErrnoException)=>{ 146 | if(e)throw Error(e.name+" "+e.code+" "+e.message+" "+e.path); 147 | complete(); 148 | }); 149 | } 150 | 151 | parseTernJson(data:JSON, distPathStr?:string):string{ 152 | this.depth = 0; 153 | 154 | let o = this.parseJsonNodeDTS(data); 155 | //console.info("-----------------------"); 156 | //console.log(JSON.stringify(o)); 157 | 158 | let d = this.preModifiedJson(o); 159 | //console.info("-----------------------"); 160 | //console.log(JSON.stringify(d)); 161 | 162 | if( 163 | this.option.isOutExport && 164 | this.userDefinedModuleName && 165 | this.option.isNodeJsModule 166 | ){ 167 | d = this.replaceExportNamespace(d); 168 | } 169 | 170 | 171 | if(this.option.isDebug){ 172 | this.saveJSON(distPathStr+".json", JSON.stringify(d), ()=>{}); 173 | } 174 | 175 | let s = this.parseToDTS(d); 176 | 177 | //add referrence paths to d.ts 178 | if(this.option.lib){ 179 | let refs = this.option.lib 180 | .map((v,i,a)=>{ 181 | return `/// `; 182 | }) 183 | .join("\n"); 184 | s = refs +"\n"+ s; 185 | } 186 | 187 | 188 | //add header 189 | s = 190 | `// Type definitions for ${this.userDefinedModuleName} 191 | // Project: [LIBRARY_URL_HERE] 192 | // Definitions by: [YOUR_NAME_HERE] <[YOUR_URL_HERE]> 193 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 194 | ` 195 | + s; 196 | 197 | if(this.option.isOutExport){ 198 | let n = this.option.exportModuleName ? this.option.exportModuleName : this.userDefinedModuleName; 199 | 200 | const reg = /^['"]([^']+)['"]$/; 201 | if(reg.test(n)){ 202 | n = RegExp.$1; 203 | } 204 | 205 | s += 206 | ` 207 | declare module '${n}' { 208 | `; 209 | if(this.option.exportStyle === dtsmake.Option.ExportStyle.ES6){ 210 | s += 211 | ` 212 | export default ${this.userDefinedModuleName}; //es6 style module export 213 | `; 214 | }else{ 215 | s += 216 | ` 217 | export = ${this.userDefinedModuleName}; //legacy ts module export 218 | `; 219 | } 220 | s += "}"+"\n"; 221 | } 222 | 223 | return s; 224 | 225 | } 226 | 227 | private modJson = {}; 228 | preModifiedJson(data:{}):Object{ 229 | let modJson = clone(data); 230 | 231 | //searching defined objects 232 | const reg = /[.]/; 233 | 234 | for(let i in modJson[TernDef.DEFINE]){ 235 | let value = modJson[TernDef.DEFINE][i]; 236 | if(typeof i === "string" && reg.test(i)){ 237 | //matched 238 | let p = i.split("."); 239 | if(p.length<=1) continue; //not defined path 240 | 241 | //naming 242 | let s = ""; 243 | if(value[0] && value[0].class && value[0].type === TSObjType.CLASS){ 244 | //already defined class 245 | let np:string[] = value[0].class.split("."); 246 | 247 | s = np[np.length-1]; 248 | 249 | }else{ 250 | s = this.resolvePathToDTSName(p); 251 | } 252 | 253 | //replace 254 | this.searchAndReplaceDTS(modJson,p,s); 255 | 256 | 257 | //save 258 | if(typeof value === "string"){ 259 | //only !type node 260 | let typeStr = value.toString(); 261 | modJson[TernDef.DEFINE][i] = {}; 262 | modJson[TernDef.DEFINE][i][TernDef.TYPE] = typeStr; 263 | //console.log("-----------------"); 264 | //console.log(JSON.stringify(value)); 265 | }else if(value instanceof Array){ 266 | if(value[0].class){ 267 | //same class instance 268 | 269 | } 270 | } 271 | 272 | modJson[TernDef.DEFINE][i][DTS_INTERFACE_STR] = s; 273 | //console.log("-----------------"); 274 | //console.log(JSON.stringify(value)); 275 | 276 | 277 | //namespace 278 | const ns = this.resolveNamespace(p); 279 | if(ns!==""){ 280 | modJson[TernDef.DEFINE][i][DTS_NAMESPACE_STR] = ns; 281 | } 282 | 283 | 284 | } 285 | } 286 | 287 | //same with js global object name 288 | const GENDOC = "\n[dtsmake] this is generated by dtsmake.\n"; 289 | for(let j in modJson){ 290 | if(typeof j === "string" && this.isJSGlobalObject(j)){ 291 | 292 | //console.log("JS Global same :"+ j) 293 | //console.log("option:"+this.option.globalObject) 294 | 295 | switch(this.option.globalObject){ 296 | case Option.GlobalObject.REMOVE: 297 | 298 | break; 299 | case Option.GlobalObject.WRAP: 300 | let n = (this.userDefinedModuleName ? this.userDefinedModuleName : "Lib");// + "." + j; 301 | if(!modJson[n]) modJson[n] = {}; 302 | let c = j; 303 | if(modJson[n][c]){ 304 | c = c + (Math.random()*1000|0); 305 | } 306 | 307 | modJson[n][c] = clone(modJson[j]); 308 | modJson[n][c][DTS_INTERFACE_STR] = c; 309 | //modJson[n][c][TernDef.TYPE] = TSObjType.FUNCTION; 310 | 311 | 312 | break; 313 | case Option.GlobalObject.RENAME: 314 | let n2 = (this.userDefinedModuleName ? this.userDefinedModuleName : "Lib") + "$" + j; 315 | if(modJson[n2]){ 316 | n2 = n2 + (Math.random()*1000|0); 317 | } 318 | 319 | modJson[n2] = {}; 320 | modJson[n2] = clone(modJson[j]); 321 | 322 | break; 323 | case Option.GlobalObject.RENAME_EXTEND: 324 | /* 325 | let n3 = (this.userDefinedModuleName ? this.userDefinedModuleName : "Lib") + "$" + j; 326 | if(modJson[n3]){ 327 | n3 = n3 + (Math.random()*1000|0); 328 | } 329 | 330 | modJson[n3] = {}; 331 | modJson[n3] = clone(modJson[j]); 332 | if(!modJson[n3][TernDef.PROTO])modJson[n3][TernDef.PROTO] = {type:TSObjType.CLASS,class:`${j}.prototype`}; 333 | console.log("modJson[n3]:"+modJson[n3]); 334 | */ 335 | break; 336 | } 337 | 338 | //remove base 339 | modJson[j] = null; 340 | delete modJson[j]; 341 | } 342 | } 343 | 344 | this.modJson = modJson; 345 | 346 | return modJson; 347 | } 348 | 349 | replaceExportNamespace(data:{}):Object{ 350 | let modJson = clone(data); 351 | 352 | //nodejs node 353 | if(modJson[TernDef.DEFINE][TernDef.NODE]){ 354 | let nodejsNode = modJson[TernDef.DEFINE][TernDef.NODE]; 355 | for(let i in nodejsNode){ 356 | //replace 357 | nodejsNode[this.userDefinedModuleName] = clone(nodejsNode[i]); 358 | 359 | //remove 360 | delete nodejsNode[i]; 361 | } 362 | } 363 | 364 | //other nodes 365 | for(let i in modJson[TernDef.DEFINE]){ 366 | let cNode = modJson[TernDef.DEFINE][i]; 367 | if(cNode[DTS_NAMESPACE_STR] &&! /\./.test(cNode[DTS_NAMESPACE_STR]) ){ 368 | //replace namespace 369 | cNode[DTS_NAMESPACE_STR] = this.userDefinedModuleName; 370 | } 371 | 372 | 373 | } 374 | 375 | if( 376 | ( 377 | modJson[this.userDefinedModuleName] && 378 | modJson[this.userDefinedModuleName] instanceof Object && 379 | Object.keys(modJson[this.userDefinedModuleName]).length === 0 380 | ) || 381 | ( 382 | modJson[this.userDefinedModuleName] && 383 | modJson[this.userDefinedModuleName] instanceof Object && 384 | Object.keys(modJson[this.userDefinedModuleName]).length === 1 && 385 | modJson[this.userDefinedModuleName][TernDef.SPAN] 386 | ) 387 | ){ 388 | //remove 389 | delete modJson[this.userDefinedModuleName]; 390 | } 391 | 392 | return modJson; 393 | } 394 | 395 | resolvePathToDTSName(paths:string[]):string{ 396 | let s = ""; 397 | const reg2 = /^!.+/; 398 | const reg3 = /<.+>/; 399 | for(let j=paths.length-1; j>0; j--){ 400 | 401 | //console.log("P[J]:"+p[j]); 402 | 403 | if(reg2.test(paths[j])){ 404 | //tern def name 405 | let tmp = paths[j] 406 | .replace("!","") 407 | .replace(/^[a-z]/,(val)=>{ 408 | return val.toUpperCase(); 409 | }); 410 | 411 | //console.log("DEFNAME:" + tmp); 412 | 413 | s = tmp + s; 414 | //console.log("DEFNAME2:" + s); 415 | } 416 | else if(reg3.test(paths[j])){ 417 | //array type 418 | let tmp = paths[j] 419 | .replace(/^$/,"") 421 | .replace(/^[a-z]/, 422 | (val)=> val.toUpperCase() 423 | ); 424 | s = tmp + s; 425 | } 426 | else if(/\//.test(paths[j])){ 427 | if(paths[j] === this.nodeModuleName){ 428 | s = this.userDefinedModuleName 429 | .replace(/^[a-z]/,(val)=>val.toUpperCase()) 430 | + s; 431 | } 432 | //console.log("DTSNAME:"+s); 433 | break; 434 | 435 | } 436 | else{ 437 | //create defined name 438 | 439 | //console.log("BEFORENAME:" + s); 440 | 441 | let s2 = paths[j].replace(/^[a-z]/,(val)=>{ 442 | return val.toUpperCase(); 443 | }); 444 | s = s2 + s; 445 | 446 | 447 | 448 | //console.log("NEW NAME: "+s); 449 | break; //end 450 | } 451 | } 452 | return s; 453 | } 454 | 455 | resolveNamespace(p:string[]):string{ 456 | let nsp:string[] = []; 457 | const len = p.length; 458 | const reg2 = /^!.+/; 459 | const reg3 = /<.+>/; 460 | 461 | const isOutRepNS = this.option.isOutExport; 462 | 463 | for(let i=len-1;i>=0;i--){ 464 | 465 | if(reg2.test(p[i]) || reg3.test(p[i])){ 466 | 467 | if(i===len-1)nsp = [];//reset 468 | else if(i>=1){ 469 | 470 | let tmpPath = ["!test",p[i-1],p[i]]; 471 | //console.log("tmpPath:"+tmpPath.join(".")) 472 | nsp.push( 473 | this.resolvePathToDTSName(tmpPath) 474 | ); 475 | 476 | } 477 | i--; 478 | continue; 479 | } 480 | 481 | 482 | if( 483 | (isOutRepNS && p[i] === this.nodeModuleName) || 484 | (isOutRepNS && /[`\/]/.test(p[i])) 485 | ){ 486 | //replace nodejs namespace 487 | if(this.userDefinedModuleName){ 488 | nsp.push(this.userDefinedModuleName); 489 | } 490 | 491 | //console.log(`nodeModule: ${this.nodeModuleName}`); 492 | //console.log(`userDifined: ${this.userDefinedModuleName}`); 493 | }else{ 494 | nsp.push(p[i]); 495 | } 496 | 497 | } 498 | return nsp.reverse().join("."); 499 | } 500 | 501 | /** 502 | * @param path searching ref path 503 | * @param name a new name to replace 504 | * @param isCheckDefine when in true, search & replace in "!define" object 505 | */ 506 | searchAndReplaceDTS( 507 | data:{}, 508 | path:string[], 509 | name:string, 510 | isCheckDefine:boolean = true 511 | ){ 512 | const len = path.length; 513 | 514 | 515 | 516 | //type check 517 | const t = path[len-1]; 518 | const rt = this.checkReplaceType(t); 519 | 520 | 521 | //search 522 | let ref = this.searchRef(data, path, isCheckDefine); 523 | if(!ref || !ref[0])return; //no path 524 | 525 | 526 | /*if(name=="GulpHeader1"){ 527 | //console.trace(); 528 | console.log("GulpHeader1:", path.join(".")); 529 | //console.log("ref:"+JSON.stringify(this.searchRef(data, path, isCheckDefine))); 530 | console.log("rt:"+rt); 531 | //console.log("resolveNamespace(path):", this.resolveNamespace(path)) 532 | };*/ 533 | 534 | //replace 535 | switch(rt){ 536 | case ReplaceType.RETURN: 537 | if(!ref || !ref[0]){ 538 | if(this.option.isDebug)console.warn("t:"+t+","+JSON.stringify(ref)); 539 | return; 540 | } 541 | let ret:TSObj[] = ref[0]["ret"]; 542 | let retLen = ret.length; 543 | 544 | if(this.option.isDebug)console.warn("Ret:", name, path, ret) 545 | 546 | if(retLen===1){ 547 | const ns = this.resolveNamespace(path) 548 | 549 | if(this.option.isDebug)console.warn("ns",ns) 550 | 551 | ret[0].class = (ns!="") ? ns+"."+name : name; 552 | ret[0].type = TSObjType.CLASS; 553 | }else{ 554 | 555 | const ns = this.resolveNamespace(path) 556 | 557 | if(this.option.isDebug)console.warn("ns",ns) 558 | 559 | //TODO:real replace 560 | let o = {}; 561 | o.class = (ns!="") ? ns+"."+name : name;//name; 562 | o.type = TSObjType.CLASS; 563 | ret.push(o); 564 | } 565 | //console.log("ret_name:"+name); 566 | //console.log(`replace[${t}]:${JSON.stringify(ref[0]["ret"])}`); 567 | break; 568 | case ReplaceType.PARAM: 569 | if(!ref || !ref[0]){ 570 | //console.log("t:"+t+","+JSON.stringify(ref)); 571 | return; 572 | } 573 | 574 | let n = Number(t.replace(/^!/,"")); 575 | 576 | 577 | //console.log(`ref:${JSON.stringify(ref)}`); 578 | //console.log(`ref[0]:${JSON.stringify(ref[0])}`); 579 | //console.log(`ref[0]["params"]:${JSON.stringify(ref[0]["params"])}`); 580 | 581 | let param = ref[0]["params"][n]; 582 | if(param instanceof Array){ 583 | let o = {}; 584 | o.class = name; 585 | o.type = TSObjType.CLASS; 586 | 587 | //if same type has, then replace 588 | const pStr = path.slice(0, path.length-2).join(".")+"."+name; 589 | let hasSameClass = (>param) 590 | .some((v,i,a)=>{ 591 | return v.class && this.resolvePathToDTSName(v.class.split(".")) === name 592 | }); 593 | 594 | //console.log("hasSameClass:", hasSameClass, name); 595 | 596 | /*let test = (>param) 597 | .some((v,i,a)=>{ 598 | return v.class && this.resolvePathToDTSName(v.class.split(".")) === name 599 | });*/ 600 | 601 | //console.log("test",test); 602 | 603 | if(hasSameClass){ 604 | (>param) 605 | .filter((v,i,a)=>{ 606 | return v.class && this.resolvePathToDTSName(v.class.split(".")) === name 607 | }) 608 | .map((v,i,a)=>{ 609 | v.type = TSObjType.CLASS; 610 | v.class = name; 611 | }); 612 | }else{ 613 | (>param).push(o); 614 | } 615 | 616 | 617 | 618 | }else{ 619 | const ns = this.resolveNamespace(path); 620 | 621 | //console.log("ns!:"+ns) 622 | 623 | param.class = (ns!="") ? ns+"."+name : name; 624 | param.type = TSObjType.CLASS; 625 | } 626 | 627 | //ref[0].class = name; 628 | //console.log(`replace[${t}]:${JSON.stringify(ref[0]["params"])}`); 629 | break; 630 | case ReplaceType.CLASS: 631 | //console.log("REP CLASS "+name); 632 | ref[0]["class"] = ""; 633 | ref[0].class = name; 634 | //console.log(`replace[${t}]:${JSON.stringify(ref[0])}`); 635 | break; 636 | case ReplaceType.ARRAY: 637 | //replacing array type 638 | 639 | let at = ref[0]["arrayType"]; 640 | 641 | let nspace = path.slice(0, path.length-2).join(".") + "." + name; 642 | 643 | let nt:TSObj = { 644 | type:TSObjType.CLASS, 645 | class:nspace 646 | }; 647 | //ref[0]["arrayType"] = nt; 648 | at[at.length-1] = nt; 649 | //console.log("REP_ARRAY:", name, JSON.stringify(at)); 650 | break; 651 | case ReplaceType.OTHER: 652 | //ref[0].class = `/* ${name} */ any`; 653 | break; 654 | } 655 | } 656 | 657 | searchRef( 658 | data:{}, 659 | path:string[], 660 | isCheckDefine:boolean 661 | ):any{ 662 | 663 | const len = path.length; 664 | if(data[path[0]]) isCheckDefine = false; 665 | 666 | let ref = isCheckDefine ? data[TernDef.DEFINE] : data; 667 | 668 | 669 | const OBJECT_TO_STRING = "$toString"; 670 | const OBJECT_VALUE_OF = "$valueOf"; 671 | 672 | for(let i=0; i0){ 693 | let pname = path.slice(0, i).join(".") +"."+ s; 694 | let iData = data[TernDef.DEFINE]; 695 | 696 | if(iData[pname]){ 697 | ref = iData[pname]; 698 | continue; 699 | } 700 | 701 | if(this.option.isDebug){ 702 | console.warn("pname", pname) 703 | console.warn("iData[pname]", JSON.stringify(iData[pname])) 704 | } 705 | } 706 | 707 | //TODO: ref path !n or !ret to searching 708 | 709 | if(this.option.isDebug){ 710 | 711 | console.warn("current ref path:"+ s); 712 | console.warn("no path ref:"+path.join(".")); 713 | console.warn("data", JSON.stringify(ref)) 714 | } 715 | 716 | 717 | return undefined; //do nothing 718 | }else{ 719 | ref = ref[s]; 720 | } 721 | } 722 | 723 | //has !type node 724 | if(ref[TernDef.TYPE]){ 725 | ref = ref[TernDef.TYPE]; 726 | } 727 | 728 | return ref; 729 | } 730 | 731 | checkReplaceType(s:string):ReplaceType{ 732 | let rt:ReplaceType; 733 | if(s === "!ret"){ 734 | //return 735 | rt = ReplaceType.RETURN; 736 | }else if(/^![0-9]+/.test(s)){ 737 | //param 738 | rt = ReplaceType.PARAM; 739 | }else if(/^[A-Z].*/.test(s)){ 740 | //class or object, may be class 741 | rt = ReplaceType.CLASS; 742 | }else if(/^<.+>$/.test(s)){ 743 | //array type 744 | rt = ReplaceType.ARRAY; 745 | //TODO:Array type replace 746 | }else{ 747 | //other 748 | rt = ReplaceType.OTHER; 749 | } 750 | return rt; 751 | } 752 | 753 | ternDefClassToDTSClass(ternClassStr:string):string{ 754 | let s = ""; 755 | 756 | //console.log("-----------CLASS-------------"); 757 | //console.log(ternClassStr); 758 | 759 | let regInstance = /^\+.*/; 760 | let regDefined = /^!.+/; 761 | if(regInstance.test(ternClassStr)){ 762 | //some class instance 763 | let p = ternClassStr.split("."); 764 | s = p[p.length-1]; 765 | }else if(regDefined.test(ternClassStr)){ 766 | //path to class 767 | 768 | let p = ternClassStr.split("."); 769 | s = this.resolvePathToDTSName(p); 770 | 771 | //console.log("-----------CLASS-------------"); 772 | //console.log(ternClassStr); 773 | 774 | 775 | 776 | 777 | //this.modJson; 778 | } 779 | 780 | return s; 781 | } 782 | 783 | /** 784 | * ternjs type definition to TSObj 785 | */ 786 | parseJsonNodeDTS(data:{}):any{ 787 | let o = JSON.parse("{}"); 788 | 789 | for(let i in data){ 790 | let value: string | {}; 791 | value = data[i]; 792 | 793 | switch(i){ 794 | //converts 795 | case TernDef.DEFINE: 796 | o[i] = {}; 797 | 798 | if(typeof value === "string")continue; 799 | else{ 800 | for(let j in value){ 801 | o[i] = this.parseJsonNodeDTS(value); 802 | } 803 | } 804 | 805 | break; 806 | case TernDef.NODE: 807 | /*if(typeof value === "string"){ 808 | this.option.isNodeJsModule = true; 809 | this.nodeModuleName = value; 810 | }else */ 811 | if(typeof i === "string"){ 812 | if(Object.keys(value).length === 1){ 813 | this.nodeModuleName = Object.keys(value)[0]; 814 | } 815 | } 816 | o[i] = this.parseJsonNodeDTS(value); 817 | break; 818 | //no converts 819 | case TernDef.NAME: 820 | this.userDefinedModuleName = value; 821 | case TernDef.DOC: 822 | case TernDef.URL: 823 | o[i] = value; 824 | break; 825 | default: 826 | 827 | 828 | if(typeof value === "string"){ 829 | //node end 830 | 831 | //Object has same name default 832 | switch(i){ 833 | case "toString": 834 | case "valueOf": 835 | let newPropName = `$${i}`; 836 | o[newPropName] = {}; 837 | o[newPropName] = this.parseTernDef(value); 838 | break; 839 | default: 840 | o[i] = this.parseTernDef(value); 841 | } 842 | }else if( 843 | value[TernDef.TYPE] && 844 | value["prototype"] 845 | ){ 846 | //has !type && .prototype 847 | o[i] = {}; 848 | 849 | //constructor 850 | o[i][DTSDef.NEW] = {}; 851 | o[i][DTSDef.NEW] = this.parseTernDef(value[TernDef.TYPE], i, true); 852 | 853 | //prototype 854 | 855 | for(let j in value["prototype"]){ 856 | if(typeof value["prototype"][j] === "string") 857 | o[i][j] = this.parseTernDef(value["prototype"][j]); 858 | else 859 | o[i][j] = this.parseJsonNodeDTS(value["prototype"][j]); 860 | } 861 | 862 | 863 | //member without prototype/!type 864 | 865 | for(let j in value){ 866 | if(j===TernDef.TYPE)continue; 867 | if(j==="prototype")continue; 868 | 869 | if(typeof value[j] === "string"){ 870 | if( 871 | j===TernDef.DOC || 872 | j===TernDef.URL 873 | ){ 874 | o[i][j] = value[j]; 875 | }else{ 876 | o[i][j] = this.parseTernDef(value[j]); 877 | } 878 | }else{ 879 | o[i][j] = this.parseJsonNodeDTS(value[j]); 880 | } 881 | 882 | } 883 | }else{ 884 | o[i] = this.parseJsonNodeDTS(value); 885 | } 886 | break; 887 | } 888 | } 889 | 890 | return o; 891 | } 892 | 893 | private isInDefine = false; 894 | private isNodeJsModule = false; 895 | private isInClassOrInterface = false; 896 | private isInObjectLiteral = false; 897 | private isNeedDeclare = true; 898 | 899 | parseToDTS(data:{}, parent?:{}):string{ 900 | let s = ""; 901 | for(let i in data){ 902 | let value:string|Object[]|Object|TSObj[]; 903 | value = data[i]; 904 | 905 | switch (i) { 906 | case TernDef.NAME: 907 | //s += `/* LIB: ${value} */\n`; 908 | break; 909 | case TernDef.DEFINE: 910 | //already defined class instance 911 | if(value instanceof Array)continue; 912 | //nothing 913 | if(typeof value === "string")continue; 914 | 915 | this.isInDefine = true; 916 | for(let j in value){ 917 | //nodejs module 918 | if(j === TernDef.NODE){ 919 | this.isNodeJsModule = true; 920 | 921 | let dont:TSObj[] = [] 922 | let wrap:TSObj[] = []; 923 | for(let k in value[TernDef.NODE]){ 924 | const v = value[TernDef.NODE][k]; 925 | if(v[TernDef.TYPE]){ 926 | dont[k] = {}; 927 | dont[k] = clone(v); 928 | } 929 | else{ 930 | wrap[k] = {}; 931 | wrap[k] = clone(v); 932 | } 933 | } 934 | 935 | 936 | //dont wrap 937 | s += this.parseToDTS(dont); 938 | 939 | 940 | //wrap 941 | s += this.wrapNamespace(wrap, TernDef.NODE); 942 | 943 | this.isNodeJsModule = false; 944 | } 945 | //global defined 946 | else{ 947 | let ns:string = ""; 948 | let defName:string = ""; 949 | if(value[j][DTS_INTERFACE_STR]){ 950 | defName = value[j][DTS_INTERFACE_STR].toString(); 951 | delete value[j][DTS_INTERFACE_STR]; 952 | }else{ 953 | defName = j; 954 | } 955 | 956 | //has namespace 957 | if(value[j][DTS_NAMESPACE_STR]){ 958 | ns = value[j][DTS_NAMESPACE_STR]; 959 | delete value[j][DTS_NAMESPACE_STR]; 960 | } 961 | 962 | //already defined no output 963 | if( 964 | value[j] instanceof Array && 965 | value[j].length === 1 && 966 | value[j][0].type === TSObjType.CLASS 967 | ){ 968 | 969 | continue; 970 | } 971 | 972 | //outputs 973 | if(ns!=""){ 974 | //namespace open 975 | s += this.indent(); 976 | s += this.addDeclare(true); 977 | s += `namespace ${ns}{\n`; 978 | this.depth++; 979 | } 980 | 981 | //type alias 982 | if(value[j] instanceof Array){ 983 | s += this.indent(); 984 | s += `// ${j}\n`; 985 | s += this.indent(); 986 | s += `type ${defName} = `; 987 | s += this.tsObjsToUnionDTS( 988 | value[j], 989 | (value[j]).some((v,i,a)=> v.type === TSObjType.FUNCTION) 990 | ); 991 | s += ";\n"; 992 | } 993 | //global variables 994 | else if(typeof value[j] === "string"){ 995 | s += this.indent(); 996 | s += this.outJSDoc( 997 | value[j][TernDef.DOC] ? value[j][TernDef.DOC] : undefined, 998 | value[j][TernDef.URL] ? value[j][TernDef.URL] : undefined 999 | ); 1000 | s += `var ${defName}: ${value[j]}\n`; 1001 | } 1002 | //interface 1003 | else{ 1004 | 1005 | s += this.interfaceDTS(defName, value[j], j); 1006 | } 1007 | 1008 | if(ns!=""){ 1009 | //namespace close 1010 | this.depth--; 1011 | s += this.indent(); 1012 | s += `}\n`; 1013 | } 1014 | } 1015 | } 1016 | this.isInDefine = false; 1017 | //} 1018 | break; 1019 | case TernDef.DOC: 1020 | //output only jsdoc 1021 | break; 1022 | case TernDef.SPAN: 1023 | break; 1024 | case TernDef.TYPE: 1025 | if(this.isInClassOrInterface){ 1026 | s += this.indent(); 1027 | s += this.convertTSObjToString( 1028 | "", 1029 | value, 1030 | value[TernDef.DOC], 1031 | value[TernDef.URL] 1032 | ); 1033 | } 1034 | break; 1035 | case TernDef.PROTO: 1036 | break; 1037 | case "": 1038 | //TODO:research ternjs def's `` mean & what to do 1039 | // Maybe ternjs cannot get prop name. 1040 | // so, currently, dtsmake don't output. 1041 | break; 1042 | default: 1043 | //grammer error name replace 1044 | if(/[\*\-]/.test(i)){ 1045 | i = `"${i}"`; 1046 | 1047 | /* 1048 | if(parent){ 1049 | parent[i] = {}; 1050 | parent[i] = clone(value); 1051 | } 1052 | break; 1053 | */ 1054 | 1055 | } 1056 | 1057 | 1058 | //node end 1059 | if(value instanceof Array){ 1060 | s += this.indent(); 1061 | s += this.convertTSObjToString(i, value, value[TernDef.DOC], value[TernDef.URL]); 1062 | } 1063 | else if(typeof value === "string"){ 1064 | s += this.outJSDoc( 1065 | value[TernDef.DOC], 1066 | value[TernDef.URL] 1067 | ); 1068 | s += this.indent(); 1069 | s += this.addDeclare(); 1070 | s += i + " : " + value; 1071 | } 1072 | //has "new ()" or "!proto" is class interface 1073 | else if( 1074 | value && (value[DTSDef.NEW] || value[TernDef.PROTO]|| value[DTS_INTERFACE_STR]) && !this.isInClassOrInterface 1075 | ){ 1076 | if( 1077 | this.option.globalObject === Option.GlobalObject.WRAP && 1078 | value[DTS_INTERFACE_STR] 1079 | ){ 1080 | delete value[DTS_INTERFACE_STR]; 1081 | } 1082 | 1083 | s += this.interfaceDTS(i,value); 1084 | 1085 | } 1086 | //has only {} node end 1087 | else if(value instanceof Object &&Object.keys(value).length===0){ 1088 | 1089 | 1090 | 1091 | s += this.indent(); 1092 | s += this.convertTSObjToString(i, [{}], value 1093 | [TernDef.DOC], value[TernDef.URL]); 1094 | } 1095 | 1096 | //has only terndef children 1097 | else if( 1098 | value && 1099 | value[TernDef.TYPE] 1100 | //TODO: other terndef node 1101 | ){ 1102 | //s += this.outJSDoc(); 1103 | s += this.indent(); 1104 | s += this.convertTSObjToString(i,value[TernDef.TYPE],value[TernDef.DOC], value[TernDef.URL]); 1105 | 1106 | //children 1107 | if(Object.keys(value).length > 1){ 1108 | let v = clone(value); 1109 | delete v[TernDef.TYPE]; 1110 | delete v[TernDef.DOC]; 1111 | delete v[TernDef.URL]; 1112 | 1113 | if(this.option.isDebug){ 1114 | console.log("I:"+i, JSON.stringify(v), Object.keys(v).length); 1115 | } 1116 | 1117 | if(Object.keys(v).length>0 && !this.isInClassOrInterface){ 1118 | //s += this.outNamespaceDTS(v, i, parent); 1119 | s += this.outNamespaceOrInterface(v,i); 1120 | } 1121 | //TODO: isInClassOrInterface == true, export namespace 1122 | } 1123 | } 1124 | //has class/interface children is namespace 1125 | else if( 1126 | this.isNamespace(value) 1127 | ){ 1128 | s += this.outNamespaceOrInterface(value, i); 1129 | 1130 | } 1131 | //has child 1132 | else{ 1133 | 1134 | s += this.outJSDoc( 1135 | value[TernDef.DOC], 1136 | value[TernDef.URL] 1137 | ); 1138 | s += this.indent(); 1139 | //object literal type 1140 | if(!this.isInObjectLiteral && !this.isInClassOrInterface){ 1141 | s += this.addDeclare(); 1142 | s += "var "; 1143 | } 1144 | s += `${i} : {\n`; 1145 | this.isInObjectLiteral = true; 1146 | this.depth++; 1147 | //s += this.indent(); 1148 | s += this.parseToDTS(value, parent); 1149 | this.depth--; 1150 | this.isInObjectLiteral = false; 1151 | s += this.indent(); 1152 | s += `}\n`; 1153 | 1154 | } 1155 | 1156 | break; 1157 | } 1158 | } 1159 | return s; 1160 | } 1161 | 1162 | addDeclare(flag?:boolean):string{ 1163 | const DECLARE_STR = "declare "; 1164 | if(flag && flag === true) return DECLARE_STR; 1165 | else if(this.depth===0) return DECLARE_STR; 1166 | else return ""; 1167 | } 1168 | 1169 | outNamespaceOrInterface(value:any, name:string, path?:string):string{ 1170 | let s = ""; 1171 | 1172 | let outI = {}; 1173 | let outN = {}; 1174 | 1175 | for(let i in value){ 1176 | if(!value[i])continue; 1177 | const v = value[i]; 1178 | 1179 | if( 1180 | v[0] && 1181 | v[0].type === TSObjType.FUNCTION && 1182 | /[\*\-]/.test(i) 1183 | ){ 1184 | //export in interface 1185 | outI[i] = clone(v); 1186 | } 1187 | /*else if( 1188 | this.isNamespace(v) || 1189 | (v[0] && this.isNamespace(v[0])) 1190 | ){ 1191 | //namespace is only child in namespace 1192 | //export in namespace 1193 | outN[i] = clone(v); 1194 | } 1195 | else if( 1196 | (v && v[DTSDef.NEW]) || 1197 | (v[0] && v[0][DTSDef.NEW]) || 1198 | (v && v[TernDef.PROTO]) || 1199 | (v[0] && v[0][TernDef.PROTO]) 1200 | ){ 1201 | //class/interface is in namespace 1202 | outN[i] = clone(v); 1203 | }*/ 1204 | else{ 1205 | //export in interface 1206 | //outI[i] = clone(v); 1207 | outN[i] = clone(v); 1208 | } 1209 | } 1210 | 1211 | if(Object.keys(outN).length>0) 1212 | s += this.outNamespaceDTS(outN, name); 1213 | if(Object.keys(outI).length>0) 1214 | s += this.interfaceDTS(name, outI); 1215 | 1216 | return s; 1217 | } 1218 | 1219 | outNamespaceDTS(value:any, name:string, parent?:any):string{ 1220 | let s = ""; 1221 | 1222 | s += this.outJSDoc( 1223 | value[TernDef.DOC], 1224 | value[TernDef.URL] 1225 | ); 1226 | s += this.indent(); 1227 | s += this.addDeclare(); 1228 | s += `namespace ${name}{\n`; 1229 | this.depth++; 1230 | s += this.parseToDTS(value, parent); 1231 | this.depth--; 1232 | s += this.indent(); 1233 | s += `}\n`; 1234 | 1235 | return s; 1236 | } 1237 | 1238 | /** 1239 | * @param defName interface name 1240 | */ 1241 | interfaceDTS( 1242 | defName:string, 1243 | value:{}|{}[], 1244 | path?:string 1245 | ):string{ 1246 | let s = ""; 1247 | 1248 | //interface name 1249 | if(path){ 1250 | s += this.indent(); 1251 | s += `// ${path}\n`; //TODO:output option ternjs internal ref path 1252 | } 1253 | s += this.outJSDoc( 1254 | value[TernDef.DOC] ? value[TernDef.DOC] : null, 1255 | value[TernDef.URL] ? value[TernDef.URL] : null 1256 | ); 1257 | s += this.indent(); 1258 | s += this.addDeclare(); 1259 | s += `interface ${defName}`; 1260 | 1261 | //extending other class/interface 1262 | if(value[TernDef.PROTO]){ 1263 | let proto = value[TernDef.PROTO]; 1264 | 1265 | if( 1266 | proto instanceof Array && 1267 | proto.length > 1 1268 | ){ 1269 | const str = "Object extends 2 or more other objects, but TypeScript only extends SINGLE Class/Interface."; 1270 | console.warn(str); 1271 | s += `/* ${str} */`; 1272 | 1273 | }else{ 1274 | 1275 | let t:TSObj = proto[0]; 1276 | 1277 | //resolve path to object prototype 1278 | if(!t.class){ 1279 | if(this.option.isDebug) 1280 | console.log("t:"+JSON.stringify(t)); 1281 | //return; 1282 | }else{ 1283 | let p = t.class.split("."); 1284 | if(p[p.length-1]==="prototype"){ 1285 | //output 1286 | let ext = p.slice(0, p.length-1).join("."); 1287 | s += ` extends ${ext}`; 1288 | } 1289 | 1290 | //delete temp property 1291 | value[TernDef.PROTO] = undefined; 1292 | delete value[TernDef.PROTO]; 1293 | } 1294 | } 1295 | } 1296 | 1297 | //interface body 1298 | this.isInClassOrInterface = true; 1299 | this.isInObjectLiteral = true; 1300 | this.isNeedDeclare = false; 1301 | s += ` {\n`; 1302 | this.depth++; 1303 | 1304 | s += this.parseToDTS(value); 1305 | 1306 | this.depth--; 1307 | s += this.indent(); 1308 | s += `}\n`; 1309 | this.isInObjectLiteral = false; 1310 | this.isInClassOrInterface = false; 1311 | this.isNeedDeclare = true; 1312 | //interface var to new() 1313 | if(value[dtsmake.DTSDef.NEW] && this.option.isExportInterfaceSameNameVar){ 1314 | s += this.indent(); 1315 | s += this.addDeclare(); 1316 | s += `var ${defName}: ${defName};\n`; 1317 | } 1318 | 1319 | return s; 1320 | } 1321 | 1322 | isNamespace(value:any):boolean{ 1323 | if(!value){ 1324 | return false; 1325 | } 1326 | else if(value instanceof Array) 1327 | return false; 1328 | else if(value[TernDef.TYPE]) 1329 | return false; 1330 | else if(!(value instanceof Object)) 1331 | return false; 1332 | else if(Object.keys(value).length === 0) 1333 | return false; 1334 | else if(this.isInClassOrInterface){ 1335 | return false; 1336 | } 1337 | else{ 1338 | 1339 | for(let i in value){ 1340 | if(!value[i])continue; 1341 | 1342 | if( 1343 | value[i] instanceof Object && 1344 | Object.keys(value[i]).length > 1 1345 | ){ 1346 | return true; 1347 | } 1348 | else if( 1349 | value[i][0] && 1350 | value[i][0].type && 1351 | ( 1352 | value[i][0].type === TSObjType.FUNCTION || 1353 | value[i][0].type === TSObjType.BOOLEAN || 1354 | value[i][0].type === TSObjType.ARRAY 1355 | ) 1356 | ){ 1357 | return true; 1358 | } 1359 | } 1360 | return false; 1361 | } 1362 | } 1363 | 1364 | /** 1365 | * 1366 | */ 1367 | outJSDoc( 1368 | comment?:string, 1369 | url?:string, 1370 | params?:string[], 1371 | ret?:string 1372 | ):string{ 1373 | let s = ""; 1374 | 1375 | //jsdoc open 1376 | s += this.indent(); 1377 | s += "\n"; 1378 | s += this.indent(); 1379 | s += `/**\n`; 1380 | 1381 | //base comment from js files 1382 | s += this.indent(); 1383 | if(comment){ 1384 | //TODO:support multi platform BR 1385 | const aComment = comment.split("\n"); 1386 | const len = aComment.length; 1387 | for(let i=0; i{ 1434 | if(v instanceof Array){ 1435 | return v[0].name; 1436 | }else{ 1437 | return v.name; 1438 | } 1439 | }) : 1440 | null; 1441 | let rs = 1442 | ( 1443 | !t.ret || 1444 | t.ret 1445 | .every((v,i,a)=>v.type === TSObjType.VOID) 1446 | ) ? 1447 | null : //no ret or void only 1448 | //t.ret.map((v,i,a)=> v.class ? v.class : "").join(", "); 1449 | //TODO:return info 1450 | " " 1451 | s += this.outJSDoc(docData,urlData,ps,rs); 1452 | return s; 1453 | } 1454 | 1455 | 1456 | convertTSObjToString( 1457 | symbolName:string, 1458 | tsObjects:TSObj[], 1459 | docData?:string, //TODO:support doc data 1460 | urlData?:string, //TODO:support url data 1461 | spanData?:string //TODO:support spandata 1462 | ):string{ 1463 | let s = ""; 1464 | let keyword = ""; 1465 | 1466 | let isFunc = false; 1467 | if(tsObjects[0].type === TSObjType.FUNCTION){ 1468 | isFunc = true; 1469 | } 1470 | 1471 | //Object property special replace revert 1472 | if(/^\$(toString|valueOf)$/.test(symbolName)){ 1473 | //console.log(symbolName+" should revert."); 1474 | symbolName = symbolName.replace(/^\$/,""); 1475 | } 1476 | 1477 | 1478 | //may be class 1479 | let isMaybeClass = false; 1480 | if( 1481 | /^[A-Z]/.test(symbolName) && //PascalCase 1482 | tsObjects[0].type === TSObjType.FUNCTION 1483 | ){ 1484 | isMaybeClass = true; 1485 | } 1486 | 1487 | //keyword 1488 | if(this.isInClassOrInterface){ 1489 | 1490 | }else if(this.isInObjectLiteral){ 1491 | 1492 | } 1493 | else{ 1494 | 1495 | if(isFunc && !isMaybeClass){ 1496 | keyword = "function "; 1497 | }else if(isFunc && isMaybeClass){ 1498 | //TODO:option class or interface (default) 1499 | keyword = "class "; 1500 | }else{ 1501 | keyword = "var "; 1502 | } 1503 | } 1504 | 1505 | //function not class/interface 1506 | if(isFunc && !isMaybeClass){ 1507 | let ol = tsObjects.length; 1508 | //TODO:overloads support 1509 | 1510 | 1511 | //out 1512 | ol = tsObjects.length; 1513 | for(let i=0;iv.type === TSObjType.VOID) 1533 | 1534 | ){ 1535 | //constructor maynot return self instance 1536 | //no output type annotation 1537 | } 1538 | else if(t.ret){ 1539 | s += `: ${this.tsObjsToUnionDTS(t.ret, (t.ret.length>1) ? true : false, t, false)}`; 1540 | } 1541 | 1542 | if(i!==ol-1){ 1543 | //overload function 1544 | s += ";"; 1545 | } 1546 | } 1547 | 1548 | 1549 | //s += keyword + symbolName + "():" + JSON.stringify(tsObjects); 1550 | } 1551 | //may be class/interface 1552 | else if(isFunc && isMaybeClass){ 1553 | 1554 | let nt:any = { 1555 | //type:TSObjType.FUNCTION, 1556 | [DTSDef.NEW]:[], 1557 | [TernDef.DOC]:docData ? docData : null//, 1558 | //[TernDef.URL]:urlData ? urlData : null 1559 | }; 1560 | if(urlData)nt[TernDef.URL] = urlData; 1561 | for(let i in tsObjects){ 1562 | if(i===TSObj.Def.TYPE)continue; 1563 | let tmp = tsObjects[i]; 1564 | //console.log("TMP:", JSON.stringify(tmp)); 1565 | tmp.ret 1566 | .filter((v,i,a)=>v.type===TSObjType.VOID) 1567 | .map((v,i,a)=>{ 1568 | //console.log("V1:",JSON.stringify(v)) 1569 | v.type = TSObjType.CLASS; 1570 | v.class = symbolName; 1571 | //console.log("V2:",JSON.stringify(v)) 1572 | return v; 1573 | }); 1574 | 1575 | nt[DTSDef.NEW].push(tmp); 1576 | } 1577 | s += this.interfaceDTS(symbolName, nt); 1578 | 1579 | /* 1580 | if(false){ 1581 | //class open 1582 | s += this.outJSDoc(docData,urlData); 1583 | s += this.indent(); 1584 | s += keyword + symbolName + "{\n"; 1585 | this.depth++; 1586 | 1587 | //constructor only 1588 | for(let i in tsObjects){ 1589 | //constructor overloads 1590 | let t = tsObjects[i]; 1591 | 1592 | //jsdoc 1593 | s += this.indent(); 1594 | s += this.outFuncJsDocs(t, docData,urlData) 1595 | 1596 | 1597 | s += this.indent(); 1598 | s += "constructor(" + this.paramsToDTS(t.params) +");\n"; 1599 | } 1600 | 1601 | //class close 1602 | this.depth--; 1603 | s += this.indent(); 1604 | s += "}"; 1605 | } 1606 | */ 1607 | } 1608 | else{ 1609 | s += this.outJSDoc( 1610 | docData, 1611 | urlData 1612 | ); 1613 | s += this.indent(); 1614 | if(!this.isInDefine && !this.isInObjectLiteral && !this.isInClassOrInterface) s += "export "; 1615 | s += this.addDeclare(); 1616 | s += keyword + symbolName+" : "+this.tsObjsToUnionDTS(tsObjects); 1617 | } 1618 | 1619 | //close ; 1620 | if(isMaybeClass)s += "\n"; 1621 | else s += ";\n"; 1622 | //this.depth--; 1623 | 1624 | return s; 1625 | } 1626 | 1627 | 1628 | 1629 | paramsToDTS(params:TSObj[]):string{ 1630 | //console.log("PARAMS:" + JSON.stringify(params)); 1631 | 1632 | if(params==null) return ""; 1633 | else 1634 | return params 1635 | .map((v, i, a)=>{ 1636 | //console.log(`|-[${i}]:${JSON.stringify(v)}`); 1637 | if(v instanceof Array){ 1638 | return this.tsObjsToUnionDTS(v, true); 1639 | }else{ 1640 | if(!v.name) v.name = `param${i+1}`; 1641 | return this.tsObjToDTS(v); 1642 | } 1643 | }) 1644 | .join(", "); 1645 | } 1646 | 1647 | /** 1648 | * @param wrap wrap params with "()" 1649 | */ 1650 | tsObjsToUnionDTS( 1651 | t:TSObj[], 1652 | wrap:boolean = false, 1653 | parentTSObj?:TSObj, 1654 | isOutName:boolean = true 1655 | ):string{ 1656 | if(!t){ 1657 | //not unions 1658 | throw Error("union needs dts any tsObjs.") 1659 | } //return "!!ERROR!!"; 1660 | 1661 | //merge `any` only union 1662 | let isOnlyAny = t 1663 | .every((v,i,a)=>(v.type === TSObjType.ANY)); 1664 | if(isOnlyAny){ 1665 | return this.tsObjToDTS(t[0], wrap, parentTSObj, isOutName); 1666 | } 1667 | 1668 | //replace `any` to `{}` or `Object` if this is not `any` only union 1669 | //because typescript type inferrence can't show union types (eg. VS Code) 1670 | let hasAny = t.some((v,i,a)=>(v.type === TSObjType.ANY)) && (t.length > 1); 1671 | if(hasAny){ 1672 | t = t.map((v,i,a)=>{ 1673 | if(v.type === TSObjType.ANY){ 1674 | v.type = TSObjType.CLASS; 1675 | v.class = "{}"; 1676 | } 1677 | return v; 1678 | }); 1679 | } 1680 | 1681 | 1682 | return t 1683 | .map((v, i, a)=>{ 1684 | let isOutParamName = isOutName; 1685 | if(i!==0) isOutParamName = false; 1686 | // v.name = null; //don't output 1687 | //if(!isOutName) v.name = null; 1688 | 1689 | return this.tsObjToDTS(v, wrap, parentTSObj, isOutParamName); 1690 | }) 1691 | .join(" | "); 1692 | } 1693 | 1694 | tsObjToDTS( 1695 | t:TSObj, 1696 | wrap:boolean = false, 1697 | parentTSObj?:TSObj, 1698 | isOutName:boolean = true 1699 | ):string{ 1700 | if(!t)return " /* error */ any"; 1701 | let s = ""; 1702 | if(t.name && isOutName) s += t.name + " : "; 1703 | wrap = wrap && (t.type === TSObjType.FUNCTION); 1704 | if(wrap) s += "("; //wrap start 1705 | switch(t.type){ 1706 | case TSObjType.ANY: 1707 | s += "any"; 1708 | break; 1709 | case TSObjType.ARRAY: 1710 | s += "Array<"+this.tsObjsToUnionDTS(t.arrayType)+">"; 1711 | 1712 | break; 1713 | case TSObjType.BOOLEAN: 1714 | s += "boolean"; 1715 | break; 1716 | case TSObjType.CLASS: 1717 | //ref to user class 1718 | 1719 | if(/^\+.+/.test(t.class)){ 1720 | //class instance 1721 | s += t.class.replace(/^\+/,""); 1722 | //TODO:check real path 1723 | } 1724 | else if(/\./.test(t.class)){ 1725 | const tp = t.class.split("."); 1726 | const last = tp[tp.length-1]; 1727 | 1728 | if(/^[A-Z].+([0-9A-Z]|Ret)$/.test(last)){ 1729 | //replaced class name 1730 | s += t.class; 1731 | }else{ 1732 | //TODO: check path exist 1733 | //temporary output 1734 | s += `/* ${t.class} */ any`; 1735 | } 1736 | } 1737 | else{ 1738 | s += t.class; 1739 | } 1740 | 1741 | //this.ternDefClassToDTSClass(t.class); 1742 | 1743 | break; 1744 | case TSObjType.FUNCTION: 1745 | //console.log("TStoDTS:fn("+t.params+")"+(t.ret)?"=>"+t.ret:""); 1746 | 1747 | s += "("+ this.paramsToDTS(t.params) +")"; 1748 | 1749 | if(!t.ret){ 1750 | t.ret = [{type:TSObjType.VOID}]; 1751 | } 1752 | s += " => " + this.tsObjsToUnionDTS(t.ret, false, null, false); 1753 | 1754 | 1755 | break; 1756 | case TSObjType.NUMBER: 1757 | s += "number"; 1758 | break; 1759 | case TSObjType.OBJECT: 1760 | if(t.class){ 1761 | 1762 | switch (this.checkReplaceType(t.class)) { 1763 | case ReplaceType.PARAM: 1764 | //TODO:replace 1765 | let n = Number(t.class.replace(/^!/, "")); 1766 | 1767 | if(!parentTSObj || !parentTSObj.params){ 1768 | s += `/*${t.class}*/ any`; 1769 | break; 1770 | } 1771 | 1772 | let rep:TSObj|TSObj[] = parentTSObj.params[n]; 1773 | // 1774 | if(rep instanceof Array){ 1775 | const isWrap = rep 1776 | .some((v,i,a)=>v.type === TSObjType.FUNCTION); 1777 | s += this.tsObjsToUnionDTS(rep,isWrap,null,false); 1778 | }else{ 1779 | s += this.tsObjToDTS(rep,false,null,false); 1780 | 1781 | if( 1782 | rep && 1783 | (rep).type && 1784 | (rep).type===TSObjType.ANY 1785 | ){ 1786 | s += ` /* same type param "${(rep).name}" */`; 1787 | //TODO:generate class/interface 1788 | } 1789 | } 1790 | 1791 | 1792 | break; 1793 | case ReplaceType.RETURN: 1794 | //TODO:replace 1795 | s += `/* ${t.class} */`; 1796 | break; 1797 | case ReplaceType.ARRAY: 1798 | //TODO:replace 1799 | s += `/* Array<${t.class}> */`; 1800 | break; 1801 | default: 1802 | if(this.isJSGlobalObject(t.class)){ 1803 | s += t.class; 1804 | }else{ 1805 | s += `/* ${t.class} */ `; 1806 | s += "any"; 1807 | } 1808 | break; 1809 | } 1810 | }else{ 1811 | s += "any"; 1812 | } 1813 | 1814 | break; 1815 | case TSObjType.STRING: 1816 | s += "string"; 1817 | break; 1818 | case TSObjType.UNIONS: 1819 | throw Error("unions? "+ JSON.stringify(t)); 1820 | //break; 1821 | case TSObjType.VOID: 1822 | if(this.option.isOutVoidAsAny) s += "/* void */ any"; 1823 | else s += "void"; 1824 | break; 1825 | default: 1826 | s += "/*no type*/{}"; //no type 1827 | break; 1828 | } 1829 | if(wrap) s += ")"; //wrap end 1830 | return s; 1831 | } 1832 | 1833 | isJSGlobalObject(name:string):boolean{ 1834 | const g:string[] = [ 1835 | "Object", 1836 | "Function", 1837 | "Boolean", 1838 | "Symbol", 1839 | "Error", 1840 | "EvalError", 1841 | "InternalError", 1842 | "RangeError", 1843 | "ReferenceError", 1844 | "SyntaxError", 1845 | "TypeError", 1846 | "URIError", 1847 | "Number", 1848 | "Math", 1849 | "Date", 1850 | "String", 1851 | "RegExp", 1852 | "Array", 1853 | "Int8Array", 1854 | "Uint8Array", 1855 | "Uint8ClampedArray", 1856 | "Int16Array", 1857 | "Uint16Array", 1858 | "Int32Array", 1859 | "Uint32Array", 1860 | "Float32Array", 1861 | "Float64Array", 1862 | "Map", 1863 | "Set", 1864 | "WeakMap", 1865 | "WeakSet", 1866 | "ArrayBuffer", 1867 | "DataView", 1868 | "JSON", 1869 | "Promise", 1870 | "Generator", 1871 | "GeneratorFunction", 1872 | "Reflect", 1873 | "Proxy" 1874 | ]; 1875 | 1876 | return g.some( (v,i,a)=> v === name); 1877 | } 1878 | 1879 | /** 1880 | * 1881 | */ 1882 | wrapNamespace(value:string|Object, nodeName:string):string{ 1883 | let s = ""; 1884 | if(typeof value === "string"){ 1885 | throw Error(nodeName +" node value must not to be string."); 1886 | }else{ 1887 | for(let j in value){ 1888 | //open namespace 1889 | s += "//nodejs module namespace\n"; 1890 | s += this.addDeclare(); 1891 | s += `namespace ${j}{\n`; 1892 | //TODO:use namespace keyword option 1893 | this.depth++; 1894 | //s += this.indent(); 1895 | s += this.parseToDTS(value[j]); 1896 | this.depth--; 1897 | //close namespace 1898 | s += `}\n`; 1899 | } 1900 | } 1901 | return s; 1902 | } 1903 | 1904 | private depth:number = 0; 1905 | indent():string{ 1906 | let s = ""; 1907 | const INDENT_STR = " "; //defalut tab string 1908 | for(let i = 0|0; (i|0)<(this.depth|0);i++){ 1909 | s += INDENT_STR; 1910 | } 1911 | return s; 1912 | } 1913 | 1914 | convertTernJsToTs(ternDef:string):TSObj{ 1915 | let ts:TSObj; 1916 | 1917 | return ts; 1918 | } 1919 | 1920 | parseTernDef(ternDef:string, parentName?:string, isConstructor:boolean = false):any[]{ 1921 | if(!ternDef) throw Error("need ternjs def string."); 1922 | 1923 | //remove spaces 1924 | ternDef = ternDef.replace(/[\s\t\n]+/g,""); 1925 | 1926 | //remove outer () 1927 | let reg = /^\((.+)\)$/; 1928 | if(reg.test(ternDef)){ 1929 | //console.log("reg:"+ternDef.match(reg)[1]); 1930 | ternDef = ternDef.match(reg)[1]; 1931 | //console.log("rm ():"+ ternDef); 1932 | } 1933 | 1934 | // 1935 | let sa = this.splitUnions(ternDef); 1936 | let ret:any[] = []; 1937 | for(let i of sa){ 1938 | let ts = {}; 1939 | ts.type = this.checkType(i); 1940 | if(parentName)ts.name = parentName; 1941 | if(ts.type === TSObjType.CLASS || ts.type === TSObjType.OBJECT){ 1942 | ts.class = i; 1943 | //console.log("++++++++++++++++++++++++"); 1944 | //console.log(" ["+i+"]:" + ts.class); 1945 | //console.log("++++++++++++++++++++++++"); 1946 | } 1947 | //console.log(`ts:${JSON.stringify(ts)}, ts.type:${ts.type}`); 1948 | switch (ts.type) { 1949 | case TSObjType.UNIONS: 1950 | ret.push(this.parseTernDef(i)); 1951 | continue; 1952 | //break; 1953 | case TSObjType.ARRAY: 1954 | //console.log("ARRAY:"+i); 1955 | //let test = i.replace(/^\[/,"").replace(/\]$/,""); 1956 | //console.log(`i.replace(/^\[/,"").replace(/\]$/,""):${test}`); 1957 | ts.arrayType = 1958 | this.parseTernDef( 1959 | i.replace(/^\[/,"").replace(/\]$/,"") 1960 | ); 1961 | break; 1962 | case TSObjType.FUNCTION: 1963 | //console.log(`fn:${i}`); 1964 | 1965 | ts.ret = this.parseFnReturn(i, parentName, isConstructor); 1966 | 1967 | ts.params = 1968 | this.parseParams(i); 1969 | break; 1970 | case TSObjType.CLASS: 1971 | case TSObjType.OBJECT: 1972 | ts.class = i; 1973 | //console.log("---CLASS/Object----"+ i + "----------"); 1974 | break; 1975 | case TSObjType.ANY: 1976 | case TSObjType.BOOLEAN: 1977 | case TSObjType.NUMBER: 1978 | default: 1979 | break; 1980 | } 1981 | ret.push(ts); 1982 | //ret.push(this.parseTernDef(i)); 1983 | } 1984 | //console.log(`ret:${JSON.stringify(ret)}`); 1985 | return ret; 1986 | } 1987 | 1988 | private parseFnReturn(fnStr:string, parentName?:string, isConstructor:boolean = false):TSObj[]{ 1989 | let sa = this.splitReturn(fnStr); 1990 | 1991 | if(isConstructor && this.option.isAnnotateTypeInstance && parentName && sa.length === 1){ 1992 | //force annotate constructor return type instance 1993 | return [{type:TSObjType.CLASS,class:parentName}]; 1994 | } 1995 | else if(sa.length===1){ 1996 | //void 1997 | return [{type:TSObjType.VOID}]; 1998 | } 1999 | 2000 | //console.log(`fn-ret:${sa[1]}`); 2001 | //return null; 2002 | /* 2003 | let ret:any[] = []; 2004 | for(let i of sa){ 2005 | ret.push(this.parseTernDef(i)); 2006 | }*/ 2007 | let ret = this.parseTernDef(sa[1]); 2008 | if(isConstructor && this.option.isAnnotateTypeInstance && parentName){ 2009 | ret 2010 | .filter((v,i,a)=>v.type===TSObjType.VOID) 2011 | .map((v,i,a)=>{ 2012 | return {type:TSObjType.CLASS,class:parentName} 2013 | }); 2014 | 2015 | } 2016 | return ret; 2017 | } 2018 | 2019 | parseParams(fnStr:string):any[]{ 2020 | let fns = this.splitReturn(fnStr)[0]; 2021 | //console.log("paramFnStr: "+fns); 2022 | let reg1 = /^fn\(/; 2023 | let reg2 = /\)$/; 2024 | //let reg3 = /.*->.*/; 2025 | 2026 | //still inner 2027 | /* 2028 | if(reg1.test(fnStr)&®2.test(fnStr)&®3.test(fnStr)){ 2029 | 2030 | }*/ 2031 | 2032 | 2033 | let fna = 2034 | reg1.test(fns) && reg2.test(fns) /*&& !reg3.test(fnStr) */? 2035 | fns 2036 | .replace(/^fn\(/, "") 2037 | .replace(/\)$/,"") : 2038 | fns; 2039 | /* 2040 | console.log( 2041 | "\u001b[32m■[check!]:\u001b[0m"+ 2042 | reg1.test(fns)+ 2043 | "^"+ 2044 | reg2.test(fns)+ 2045 | //"^"+ 2046 | //!reg3.test(fnStr)+ 2047 | ",\n"+ 2048 | fna 2049 | );*/ 2050 | 2051 | if(!fna || fna.length===1){ 2052 | //console.log("no params. : "+fnStr) 2053 | return null; 2054 | }else{ 2055 | let paramStr = fna; 2056 | //console.log("param_str[1]:"+ paramStr); 2057 | //return; 2058 | //* 2059 | let sa = this.splitParams(paramStr); 2060 | 2061 | //console.log(`param_str[2]:${sa}, len:${sa.length}`) 2062 | 2063 | let ret:any[] = []; 2064 | for(let i of sa){ 2065 | let n = i.search(/:/); 2066 | let name = (n===-1) ? null : i.substring(0,n); 2067 | let sType = i.substring(n+1); 2068 | //console.log(`sType:${sType}`); 2069 | let checked = this.checkType(sType); 2070 | if(TSObjType.UNIONS === checked){ 2071 | //unions 2072 | 2073 | let pa = this.parseTernDef(sType, name); 2074 | ret.push(pa); 2075 | } 2076 | else if(TSObjType.ARRAY === checked){ 2077 | let a = this.parseTernDef(sType,name); 2078 | if(a.length===1){ 2079 | ret.push(a[0]); 2080 | }else{ 2081 | ret.push(a); 2082 | } 2083 | 2084 | } 2085 | else{ 2086 | 2087 | let ts = {}; 2088 | if(n!==-1)ts.name = name; 2089 | ts.type = checked; 2090 | 2091 | if( 2092 | ts.type === TSObjType.OBJECT || 2093 | ts.type === TSObjType.CLASS 2094 | ){ 2095 | ts.class = sType; 2096 | } 2097 | 2098 | 2099 | //if(n===-1)console.log(`ts:${ts.name},${ts.type}`); 2100 | ret.push(ts); 2101 | } 2102 | } 2103 | 2104 | return ret; 2105 | } 2106 | 2107 | } 2108 | 2109 | /** 2110 | * ternjs type to typescript type enum 2111 | * | (a|b) | UNIONS | 2112 | * | fn() | FUNCTION | 2113 | * | ? | ANY | 2114 | * | bool | BOOLEAN | 2115 | * | number| NUMBER | 2116 | * | string| STRING | 2117 | * | [?] | ARRAY | 2118 | * | +abc | CLASS | 2119 | * | other above | OBJECT | 2120 | * @return TSObjType return enums (number) 2121 | */ 2122 | checkType(ternDef:string):TSObjType{ 2123 | if(this.splitUnions(ternDef).length>1){ 2124 | return TSObjType.UNIONS; 2125 | }else if(/^fn\(/.test(ternDef)){ 2126 | //function 2127 | return TSObjType.FUNCTION; 2128 | }else if(ternDef==="?"){ 2129 | return TSObjType.ANY; 2130 | }else if(ternDef==="bool"){ 2131 | return TSObjType.BOOLEAN; 2132 | }else if(ternDef==="number"){ 2133 | return TSObjType.NUMBER; 2134 | }else if(ternDef==="string"){ 2135 | return TSObjType.STRING; 2136 | }else if(/^\[.+\]$/.test(ternDef)){ 2137 | return TSObjType.ARRAY; 2138 | }else if(/^\+.+$/.test(ternDef)){ 2139 | return TSObjType.CLASS; 2140 | }else if(ternDef!=""){ 2141 | //console.log(`\u001b[35mWARNING: \u001b[0m ${ternDef} may not be type string. Is this a Object?`); 2142 | return TSObjType.OBJECT; 2143 | }else{ 2144 | throw Error("\u001b[31mcan not check type. : \u001b[0m"+ternDef); 2145 | //return; 2146 | } 2147 | } 2148 | 2149 | private splitUnions(ternDef:string):string[]{ 2150 | return this.splits(ternDef, "(", ")", "|"); 2151 | } 2152 | 2153 | splitParams(paramStr:string):string[]{ 2154 | return this.splits(paramStr, "(", ")", ","); 2155 | } 2156 | 2157 | private splitReturn(fnStr:string):string[]{ 2158 | return this.splits(fnStr, "(",")","->"); 2159 | } 2160 | 2161 | private splits( 2162 | str:string, 2163 | depthUpStr:string, 2164 | depthDownStr:string, 2165 | splitter:string 2166 | ):string[]{ 2167 | let delimIdxs:number[] = []; 2168 | let retStr:any[] = []; 2169 | const len = str.length|0; 2170 | let depth = 0; 2171 | 2172 | 2173 | 2174 | //* 2175 | const dUpIni = depthUpStr.charAt(0); 2176 | const dDwIni = depthDownStr.charAt(0); 2177 | const splIni = splitter.charAt(0); 2178 | for(let i = 0|0;(i|0)<(len|0);i=(i+1)|0){ 2179 | let cs = str.charAt(i); 2180 | 2181 | switch (cs) { 2182 | case dUpIni: 2183 | depth++; 2184 | break; 2185 | case dDwIni: 2186 | depth--; 2187 | break; 2188 | case splIni: 2189 | if(str.substr(i, splitter.length) != splitter) break; 2190 | if(depth===0){ 2191 | delimIdxs.push(i); 2192 | i += splitter.length; 2193 | } 2194 | break; 2195 | default: 2196 | break; 2197 | } 2198 | 2199 | }//*/ 2200 | 2201 | const delimLen = delimIdxs.length; 2202 | if(delimLen===0){ 2203 | retStr.push(str); 2204 | }else{ 2205 | 2206 | let start = 0; 2207 | let end = 0; 2208 | 2209 | for(let j=0;j `lib.Math` 2345 | */ 2346 | export const WRAP = "wrap"; 2347 | /** 2348 | * renaming global objects 2349 | * @example `Math` -> `Lib$Math` 2350 | */ 2351 | export const RENAME = "rename"; 2352 | /** 2353 | * renaming global objects and extending global object 2354 | * @example `Math` -> `Lib$Math extends Math` 2355 | * [NEED] tsc >= 1.6 2356 | */ 2357 | export const RENAME_EXTEND = "renameExtend"; 2358 | } 2359 | 2360 | export namespace dtsmake.TernDef{ 2361 | export const NAME = "!name"; 2362 | export const DEFINE = "!define"; 2363 | export const TYPE = "!type"; 2364 | export const DOC = "!doc"; 2365 | export const URL = "!url"; 2366 | export const EFFECTS = "!effects"; 2367 | export const THIS = "!this"; 2368 | export const RET = "!ret"; 2369 | export const SPAN = "!span"; 2370 | export const PROTO = "!proto"; 2371 | export const STR_PROTO = "!stdProto"; 2372 | export const NODE = "!modules"; 2373 | 2374 | /** 2375 | * convert TernDef.CONST:string to EnumTernDef.CONST:number 2376 | * @param s TernDef class prop constraint string 2377 | * @return EnumTernDef enum 2378 | */ 2379 | export function strToEnum(s:string):EnumTernDef{ 2380 | switch (s) { 2381 | case this.NAME: return EnumTernDef.NAME;//break; 2382 | case this.DEFINE: return EnumTernDef.DEFINE;//break; 2383 | case this.TYPE: return EnumTernDef.TYPE;//break; 2384 | case this.DOC: return EnumTernDef.DOC;//break; 2385 | case this.URL: return EnumTernDef.URL;//break; 2386 | case this.EFFECTS: return EnumTernDef.EFFECTS;//break; 2387 | case this.THIS: return EnumTernDef.THIS;//break; 2388 | case this.RET: return EnumTernDef.RET;//break; 2389 | case this.SPAN: return EnumTernDef.SPAN;//break; 2390 | case this.PROTO: return EnumTernDef.PROTO;//break; 2391 | case this.STD_PROTO: return EnumTernDef.STR_PROTO;//break; 2392 | case this.NODE: return EnumTernDef.NODE;//break; 2393 | default: 2394 | throw Error("no match enum strings:"+s); 2395 | //break; 2396 | } 2397 | } 2398 | } 2399 | /////////////////////////////// 2400 | // CLI 2401 | ////////////////////////////// 2402 | //var dgen = new dtsmake.DTSMake(); 2403 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * dtsmake command line interface 4 | */ 5 | 6 | import * as program from "commander"; 7 | import {dtsmake} from "./dtsmake"; 8 | import * as child_process from "child_process"; 9 | var myPackage = require("../package.json"); 10 | 11 | 12 | var srcFiles = (val:string):string[]=>{ 13 | return val.split(","); 14 | }; 15 | var plugins = (val:string):string[]=>{ 16 | return val.split(","); 17 | } 18 | //var distDir:string = ""; 19 | var defFiles = function(val:string):string[]{ 20 | return val.split(","); 21 | } 22 | var extraFiles = function(val:string):string[]{ 23 | console.log("[EXTRA]"+val); 24 | return val.split(","); 25 | } 26 | 27 | var libDTSs = (val:string):string[]=>{ 28 | return val.split(","); 29 | } 30 | 31 | 32 | program 33 | .version(myPackage.version, "-v, --version") 34 | // command 35 | /* 36 | .command("gen [srcFiles...] ") 37 | .action((src:string[], dist:string)=>{ 38 | src 39 | .map((v,i,a)=>{ 40 | console.log(`srcFiles[${i}]:${v.toString()}\n`); 41 | }); 42 | console.log(`distDir: ${dist}`); 43 | srcFiles = src; 44 | distDir = dist; 45 | })*/ 46 | .option("-s, --src ", "[MUST] target javascript file path", srcFiles) 47 | .option("--dist [value]", "outout d.ts file path. no need `.d.ts` file extension.") 48 | 49 | // ternjs bridge options 50 | .option("-n, --n [value]", "module name") 51 | .option("-p, --plugin ", "tern.js plugin. see tern.js server plugin(http://ternjs.net/doc/manual.html#plugins)", plugins) 52 | .option("-d, --def ","tern.js def files. DEFAULT:'ecma5'", defFiles) 53 | .option("-x, --extrafiles ", "sample files for target js lib. help for ternjs type inference.", extraFiles) 54 | 55 | // dtsmake options 56 | .option("-D, --debug", "debug output mode") 57 | .option("-A, --voidAsAny", "force output `void` to `any`") 58 | .option("-i, --interfaceSameNameVar", "export a namespace property same with a interface name", true) 59 | .option("-a, --annotateTypeInstance", "annotate interface's constructor type as return type instance", true) 60 | .option("-g, --globalObject [value]", `how to export objects that same name with JS Global Object; "remove" or "wrap" or "rename"; DEFAULT:"wrap" `) 61 | .option("-N, --NodeJSModule", "nodejs module special replace") 62 | .option("-e, --export", "add export statement in a bottom of d.ts file") 63 | .option("-S, --exportStyle [value]", `if --outExport true, select export style "es6" or "legacy"`) 64 | .option("-M, --exportModuleName [value]", 'exporting module name. ex. "EXAMPLE"; usage `import example = require("EXAMPLE");`') 65 | .option("-l, --lib ", "add referrece path d.ts files. ex. `--lib path/to/ex1.d.ts,path/to/ex2.d.ts`", libDTSs) 66 | 67 | .parse(process.argv); 68 | 69 | 70 | if(!(program).src) { 71 | console.warn("--src option is MUST."); 72 | program.help(); 73 | } 74 | else if((program).exportStyle && !(program).export){ 75 | console.warn("--exportStyle option needs --export option.") 76 | process.exit(1); 77 | } 78 | else if((program).exportModuleName && !(program).export){ 79 | console.warn("--exportModuleName option needs --export option.") 80 | process.exit(1); 81 | } 82 | 83 | /** 84 | * 85 | * `tern/bin/condense [--name name] [--plugin name]* [--def name]* [+extrafile.js]* [file.js]+` 86 | */ 87 | var genCommand = (version:string, path:string)=>{ 88 | var s = ""; 89 | const major = Number(version.split(".")[0]); 90 | //console.log(`genCommand`) 91 | //const px = `"${__dirname}"` 92 | //console.log(`p:${path}`) 93 | 94 | if(major >= 3){ 95 | 96 | //for npm >= v3.0 97 | //const p = require("tern/bin/condense").resolve() 98 | //console.log(`p:${p}`) 99 | //throw Error(`hi`) 100 | s = `node "${path}/tern/bin/condense"` 101 | }else{ 102 | //for npm < v3.x 103 | s = `node "${__dirname}/../node_modules/tern/bin/condense"`; 104 | } 105 | 106 | s += (program).n ? ` --name ${(program).n}` : ""; 107 | //s += (program).plugin ? ` --plugin ${(program).plugin.join(" ")}` : ""; 108 | if((program).plugin){ 109 | for(let i in (program).plugin){ 110 | s += ` --plugin ${(program).plugin[i]}`; 111 | } 112 | } 113 | //s += (program).def ? ` --def ${(program).def.join(" ")}` : ""; 114 | if((program).def){ 115 | for(let i in (program).def){ 116 | s += ` --def ${(program).def[i]}`; 117 | } 118 | } 119 | s += (program).extrafiles ? ` +${(program).extrafiles.join(" +")}` : ""; 120 | s += " " + (program).src.join(" "); 121 | s += " --no-spans"; 122 | 123 | console.log(`${program.name()} started.`); 124 | console.log("[CMD]"+s); 125 | console.log("[SRC]"+(program).src.join(" ")); 126 | return s; 127 | } 128 | 129 | function npmVersion(cb:(v:string,e:Error)=>void){ 130 | child_process.exec( 131 | "npm -v", 132 | {encoding:"utf8",maxBuffer:2048}, 133 | (e:Error, stdout:Buffer, stderr:Buffer)=>{ 134 | //if(e)throw e; 135 | cb(stdout.toString(), e); 136 | } 137 | ) 138 | } 139 | function getDirNodeModules(cb:(p:string,e:Error)=>void){ 140 | child_process.exec( 141 | "npm root", 142 | {encoding:"utf8",maxBuffer:2048}, 143 | (e:Error, stdout:Buffer, stderr:Buffer)=>{ 144 | //if(e)throw e; 145 | cb(stdout.toString().replace(/[\r\n]/g,""), e); 146 | } 147 | ) 148 | } 149 | 150 | getDirNodeModules((path:string, e:Error)=>{ 151 | npmVersion((version:string, e2:Error)=>{ 152 | console.log(`v:${version}`) 153 | exec(version,path); 154 | }) 155 | }) 156 | 157 | /** 158 | * exec tern/bin/condense 159 | */ 160 | function exec(version:string,path:string){ 161 | var child = child_process.exec( 162 | genCommand(version,path), 163 | {maxBuffer: 1000000*2048}, 164 | (err:Error, stdout:string, stderr:string)=>{ 165 | if(err){ 166 | console.warn("[INFO] tern/condense error"); 167 | console.error(err.toString()); 168 | return; 169 | } 170 | else if(stderr){ 171 | console.warn("[INFO] tern/condense error"); 172 | console.error(stderr.toString()); 173 | return; 174 | } 175 | else{ 176 | if((program).debug)console.log(stdout.toString()); 177 | 178 | // 179 | let dg = new dtsmake.DTSMake(); 180 | let op:dtsmake.Option = 181 | { 182 | isDebug: (program).debug, 183 | isOutVoidAsAny: (program).voidAsAny, 184 | isAnnotateTypeInstance: (program).annotateTypeInstance, 185 | isExportInterfaceSameNameVar: (program).interfaceSameNameVar, 186 | isNodeJsModule: (program).NodeJSModule, 187 | isOutExport: (program).export, 188 | }; 189 | if((program).exportStyle) op.exportStyle = (program).exportStyle; 190 | if((program).exportModuleName) op.exportModuleName = (program).exportModuleName; 191 | if((program).globalObject) op.globalObject = (program).globalObject; 192 | if((program).lib) op.lib = (program).lib; 193 | 194 | dg.main( 195 | stdout.toString(), 196 | (program).dist ? (program).dist : (program).src.toString().replace(/\.[a-z0-9]+$/,""), 197 | op 198 | ); 199 | } 200 | } 201 | ); 202 | } 203 | 204 | -------------------------------------------------------------------------------- /test/dtsout-test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'power-assert'; 2 | import {dtsmake} from '../src/dtsmake'; 3 | import fs = require('fs'); 4 | 5 | describe("TypeScript d.ts file output tests,", ()=>{ 6 | 7 | let dg = new dtsmake.DTSMake(); 8 | 9 | 10 | context("tsObjToDTS()", ()=>{ 11 | 12 | it("shoud be replace ternjs Class instance path",()=>{ 13 | const p = [ 14 | { 15 | type:dtsmake.TSObjType.CLASS, 16 | name:"param", 17 | class:"+Klass" 18 | } 19 | ]; 20 | let out = dg.tsObjToDTS(p[0]); 21 | let answer = "param : Klass" 22 | assert(out === answer, `out strings should be ${answer}.`); 23 | 24 | }); 25 | 26 | it("should be replace ternjs array",()=>{ 27 | const to = { 28 | type:dtsmake.TSObjType.ARRAY, 29 | arrayType:[ 30 | { 31 | type:dtsmake.TSObjType.ANY 32 | } 33 | ] 34 | }; 35 | 36 | let out = dg.tsObjToDTS(to); 37 | let answer = "Array"; 38 | assert(out === answer, `out strings ${out} should be ${answer}.`); 39 | }); 40 | 41 | 42 | it.skip("shoud be replace ternjs !ret",()=>{ 43 | const p = [ 44 | { 45 | type:dtsmake.TSObjType.OBJECT, 46 | name:"param", 47 | class:"!ret" 48 | } 49 | ]; 50 | let out = dg.tsObjToDTS(p[0]); 51 | let answer = "param : /* !ret */" 52 | assert(out === answer, `out strings should be ${answer}.`); 53 | 54 | }); 55 | 56 | it("should convert JS native global objects",()=>{ 57 | const g = [ 58 | "Object", 59 | "Function", 60 | "Boolean", 61 | "Symbol", 62 | "Error", 63 | "EvalError", 64 | "InternalError", 65 | "RangeError", 66 | "ReferenceError", 67 | "SyntaxError", 68 | "TypeError", 69 | "URIError", 70 | "Number", 71 | "Math", 72 | "Date", 73 | "String", 74 | "RegExp", 75 | "Array", 76 | "Int8Array", 77 | "Uint8Array", 78 | "Uint8ClampedArray", 79 | "Int16Array", 80 | "Uint16Array", 81 | "Int32Array", 82 | "Uint32Array", 83 | "Float32Array", 84 | "Float64Array", 85 | "Map", 86 | "Set", 87 | "WeakMap", 88 | "WeakSet", 89 | "ArrayBuffer", 90 | "DataView", 91 | "JSON", 92 | "Promise", 93 | "Generator", 94 | "GeneratorFunction", 95 | "Reflect", 96 | "Proxy" 97 | ]; 98 | 99 | let p:dtsmake.TSObj[] = []; 100 | let answer:string[] = []; 101 | let out:string[] = []; 102 | for(let i in g){ 103 | let o:dtsmake.TSObj = {type:9, name:"a"+i, class:""}; 104 | o.class = g[i]; 105 | p.push(o); 106 | 107 | answer.push(`a${i} : ${g[i]}`); 108 | 109 | out.push(dg.tsObjToDTS(p[p.length-1])); 110 | } 111 | 112 | assert.deepEqual(out, answer); 113 | 114 | 115 | }) 116 | 117 | }); 118 | 119 | context("paramsToDTS()", ()=>{ 120 | 121 | it("should be able to replace ternjs Class instance path", ()=>{ 122 | 123 | const p = [ 124 | { 125 | type:dtsmake.TSObjType.CLASS, 126 | name:"param", 127 | class:"+Klass" 128 | } 129 | ]; 130 | 131 | let out = dg.paramsToDTS(p); 132 | let answer = "param : Klass" 133 | assert(out === answer); 134 | 135 | }) 136 | }); 137 | 138 | context("convertTSObjToString()", ()=>{ 139 | 140 | beforeEach(()=>{ 141 | dg["depth"] = 0; 142 | }) 143 | 144 | 145 | it("should convert simple function", ()=>{ 146 | const def:dtsmake.TSObj[] = [ 147 | { 148 | type:dtsmake.TSObjType.FUNCTION, 149 | ret:[ 150 | {type:dtsmake.TSObjType.NUMBER}, 151 | {type:dtsmake.TSObjType.STRING}, 152 | ], 153 | params:null 154 | } 155 | ]; 156 | const defName = "example"; 157 | 158 | const out = dg.convertTSObjToString(defName,def); 159 | const answer = 160 | ` 161 | /** 162 | * 163 | * @return 164 | */ 165 | declare function ${defName}(): number | string; 166 | `; 167 | 168 | assert.deepEqual(out, answer); 169 | 170 | }); 171 | 172 | it("should convert constructor without return type annotation", ()=>{ 173 | const def:dtsmake.TSObj[] = [ 174 | { 175 | type:dtsmake.TSObjType.FUNCTION, 176 | ret:[ 177 | {type:dtsmake.TSObjType.VOID} 178 | ], 179 | params:null 180 | } 181 | ]; 182 | const defName = "new "; 183 | dg.option.isAnnotateTypeInstance = false; 184 | const out = dg.convertTSObjToString(defName,def); 185 | const answer = 186 | ` 187 | /** 188 | * 189 | */ 190 | declare function ${defName}(); 191 | `; 192 | 193 | assert.deepEqual(out, answer); 194 | 195 | }); 196 | 197 | it("should convert constructor with return type annotation", ()=>{ 198 | const def:dtsmake.TSObj[] = [ 199 | { 200 | type:dtsmake.TSObjType.FUNCTION, 201 | ret:[ 202 | {type:dtsmake.TSObjType.VOID} 203 | ], 204 | params:null 205 | } 206 | ]; 207 | const defName = "new "; 208 | dg.option.isAnnotateTypeInstance = true; 209 | dg.option.isOutVoidAsAny = false; 210 | const out = dg.convertTSObjToString(defName,def); 211 | const answer = 212 | ` 213 | /** 214 | * 215 | */ 216 | declare function ${defName}(): void; 217 | `; 218 | 219 | assert.deepEqual(out, answer); 220 | 221 | }); 222 | 223 | it("should convert constructor with return type annotation void as any", ()=>{ 224 | const def:dtsmake.TSObj[] = [ 225 | { 226 | type:dtsmake.TSObjType.FUNCTION, 227 | ret:[ 228 | {type:dtsmake.TSObjType.VOID} 229 | ], 230 | params:null 231 | } 232 | ]; 233 | const defName = "new "; 234 | dg.option.isAnnotateTypeInstance = true; 235 | dg.option.isOutVoidAsAny = true; 236 | const out = dg.convertTSObjToString(defName,def); 237 | const answer = 238 | ` 239 | /** 240 | * 241 | */ 242 | declare function ${defName}(): /* void */ any; 243 | `; 244 | 245 | assert.deepEqual(out, answer); 246 | 247 | }); 248 | 249 | it("should not output ret name prop", ()=>{ 250 | const def:dtsmake.TSObj[] = [ 251 | { 252 | type:dtsmake.TSObjType.FUNCTION, 253 | ret:[ 254 | { 255 | type:dtsmake.TSObjType.NUMBER, 256 | name:"notOutput" 257 | }, 258 | { 259 | type:dtsmake.TSObjType.STRING, 260 | name:"notOutput" 261 | }, 262 | ], 263 | params:null 264 | } 265 | ]; 266 | const defName = "example"; 267 | 268 | const out = dg.convertTSObjToString(defName,def); 269 | const answer = 270 | ` 271 | /** 272 | * 273 | * @return 274 | */ 275 | declare function ${defName}(): number | string; 276 | `; 277 | 278 | assert.deepEqual(out, answer); 279 | 280 | }); 281 | 282 | it("should wrap fn() return type", ()=>{ 283 | const def:dtsmake.TSObj[] = [ 284 | { 285 | type:dtsmake.TSObjType.FUNCTION, 286 | ret:[ 287 | { 288 | type:dtsmake.TSObjType.OBJECT, 289 | class:"sinon.collection.stub.!ret" 290 | }, 291 | { 292 | type:dtsmake.TSObjType.FUNCTION, 293 | params:null, 294 | ret:[ 295 | {type:dtsmake.TSObjType.VOID} 296 | ] 297 | }, 298 | ], 299 | params:null 300 | } 301 | ]; 302 | const defName = "example"; 303 | dg.option.isOutVoidAsAny = false; 304 | const out = dg.convertTSObjToString(defName,def); 305 | const answer = 306 | ` 307 | /** 308 | * 309 | * @return 310 | */ 311 | declare function ${defName}(): /* sinon.collection.stub.!ret */ any | (() => void); 312 | `; 313 | 314 | assert.deepEqual(out, answer); 315 | 316 | }); 317 | 318 | 319 | it("should wrap fn() return type2", ()=>{ 320 | const def = [ 321 | { 322 | type:dtsmake.TSObjType.FUNCTION, 323 | ret:[ 324 | { 325 | type:dtsmake.TSObjType.OBJECT, 326 | class:"!0" 327 | } 328 | ], 329 | params:[ 330 | [ 331 | {"type":9,"name":"fake","class":"sinon.collection.stub.!ret"}, 332 | {"type":5,"name":"fake","ret":[{"type":1}], 333 | "params":null} 334 | ] 335 | ] 336 | } 337 | ]; 338 | const defName = "add"; 339 | dg.option.isOutVoidAsAny = false; 340 | const out = dg.convertTSObjToString(defName,def); 341 | const answer = 342 | ` 343 | /** 344 | * 345 | * @param fake 346 | * @return 347 | */ 348 | declare function ${defName}(fake : /* sinon.collection.stub.!ret */ any | (() => void)): /* sinon.collection.stub.!ret */ any | (() => void); 349 | `; 350 | 351 | assert.deepEqual(out, answer); 352 | 353 | }); 354 | 355 | }); 356 | 357 | context("parseToDTS()", ()=>{ 358 | it("should convert !type only interface",()=>{ 359 | const def = { 360 | "!define":{ 361 | "!node.``/node_modules/tern/lib/tern`js.Server.prototype.flush.!0": { 362 | "!type": [ 363 | { 364 | "type": 5, 365 | "ret": [ 366 | { 367 | "type": 1 368 | } 369 | ], 370 | "params": null 371 | } 372 | ], 373 | "!span": [ 374 | { 375 | "type": 9, 376 | "class": "6371[214:6]-6643[223:7]" 377 | } 378 | ], 379 | "!!!dtsinterface!!!": "Flush0", 380 | "!!!dtsnamespace!!!": "tern" 381 | } 382 | } 383 | }; 384 | dg.option.isOutVoidAsAny = false; 385 | const out = dg.parseToDTS(def); 386 | const st = "!node.``/node_modules/tern/lib/tern`js.Server.prototype.flush.!0"; 387 | const ans = 388 | `declare namespace tern{ 389 | // ${st} 390 | 391 | /** 392 | * 393 | */ 394 | interface Flush0 { 395 | 396 | /** 397 | * 398 | */ 399 | (): void; 400 | } 401 | } 402 | `; 403 | assert.deepEqual(out,ans); 404 | 405 | 406 | }); 407 | 408 | 409 | it("should not convert prop (maybe ternjs internal def)",()=>{ 410 | 411 | const def = { 412 | "!define":{ 413 | "passes": { 414 | "": { 415 | "!type": [ 416 | { 417 | "type": 6, 418 | "arrayType": [ 419 | { 420 | "type": 0 421 | } 422 | ] 423 | } 424 | ], 425 | "!span": [ 426 | { 427 | "type": 9, 428 | "class": "3425[113:43]-3429[113:47]" 429 | } 430 | ] 431 | }, 432 | "!span": [ 433 | { 434 | "type": 9, 435 | "class": "2904[103:9]-2910[103:15]" 436 | } 437 | ] 438 | } 439 | } 440 | }; 441 | dg.option.isOutVoidAsAny = false; 442 | dg["isInInterfaceOrClass"] = true; 443 | const out = dg.parseToDTS(def); 444 | const ans = 445 | `// passes 446 | 447 | /** 448 | * 449 | */ 450 | declare interface passes { 451 | } 452 | `; 453 | assert.deepEqual(out, ans); 454 | 455 | }); 456 | 457 | it("should convert node.js node correctly",()=>{ 458 | let def = { 459 | "!define": { 460 | "!modules": { 461 | "gulpHeader": { 462 | "!type": [ 463 | { 464 | "type": 5, 465 | "ret": [ 466 | { 467 | "type": 0 468 | } 469 | ], 470 | "params": [ 471 | { 472 | "name": "headerText", 473 | "type": 4 474 | }, 475 | { 476 | "name": "data", 477 | "type": 7, 478 | "class": "GulpHeader1" 479 | } 480 | ] 481 | }, 482 | { 483 | "type": 5, 484 | "ret": [ 485 | { 486 | "type": 0 487 | } 488 | ], 489 | "params": [ 490 | { 491 | "name": "override", 492 | "type": 0 493 | } 494 | ] 495 | } 496 | ], 497 | "!doc": "gulp-header plugin" 498 | } 499 | } 500 | } 501 | }; 502 | 503 | dg.option.isOutVoidAsAny = false; 504 | const out = dg.parseToDTS(def); 505 | const ans = 506 | ` 507 | /** 508 | * gulp-header plugin 509 | * @param headerText 510 | * @param data 511 | * @return 512 | */ 513 | declare function gulpHeader(headerText : string, data : GulpHeader1): any; 514 | /** 515 | * gulp-header plugin 516 | * @param override 517 | * @return 518 | */ 519 | declare function gulpHeader(override : any): any; 520 | `; 521 | assert.deepEqual(out, ans); 522 | 523 | }); 524 | 525 | 526 | 527 | }); 528 | 529 | 530 | context("outJSDoc()", ()=>{ 531 | 532 | beforeEach(()=>{ 533 | dg["depth"] = 0; 534 | }) 535 | 536 | it("should output simple jsdoc",()=>{ 537 | const c = "COMMENT"; 538 | const u = "http://example.jp/"; 539 | const p = ["hoge","fuga"]; 540 | const r = "RETURN"; 541 | 542 | const out = dg.outJSDoc(c,u,p,r); 543 | const answer = 544 | ` 545 | /** 546 | * ${c} 547 | * @param ${p[0]} 548 | * @param ${p[1]} 549 | * @return ${r} 550 | * @url ${u} 551 | */ 552 | `; 553 | assert.deepEqual(out, answer); 554 | 555 | }); 556 | 557 | 558 | it("should output multiline jsdoc",()=>{ 559 | dg["depth"] = 1; 560 | const c = "COMMENT\nMULTILINE\nSAMPLE"; 561 | const u = "http://example.jp/"; 562 | const p = ["hoge","fuga"]; 563 | const r = "RETURN"; 564 | 565 | const out = dg.outJSDoc(c,u,p,r); 566 | const answer = 567 | ` 568 | /** 569 | * COMMENT 570 | * MULTILINE 571 | * SAMPLE 572 | * @param ${p[0]} 573 | * @param ${p[1]} 574 | * @return ${r} 575 | * @url ${u} 576 | */ 577 | `; 578 | assert.deepEqual(out, answer); 579 | dg["depth"]--; 580 | }) 581 | 582 | }); 583 | 584 | 585 | 586 | context("outFuncJsDocs()", ()=>{ 587 | 588 | beforeEach(()=>{ 589 | dg["depth"] = 0; 590 | }) 591 | 592 | it("should output simple function jsdoc",()=>{ 593 | const t:dtsmake.TSObj = { 594 | type:dtsmake.TSObjType.FUNCTION, 595 | params:[ 596 | { 597 | type:dtsmake.TSObjType.NUMBER, 598 | name:"hoge" 599 | }, 600 | { 601 | type:dtsmake.TSObjType.STRING, 602 | name:"fuga" 603 | } 604 | ], 605 | ret:[ 606 | { 607 | type:dtsmake.TSObjType.NUMBER 608 | }, 609 | { 610 | type:dtsmake.TSObjType.STRING 611 | } 612 | ] 613 | }; 614 | 615 | const out = dg.outFuncJsDocs(t); 616 | const answer = 617 | ` 618 | /** 619 | * 620 | * @param hoge 621 | * @param fuga 622 | * @return 623 | */ 624 | `; 625 | assert.deepEqual(out, answer); 626 | }); 627 | }); 628 | 629 | 630 | context("addDeclare()", ()=>{ 631 | beforeEach(()=>{ 632 | dg["depth"] = 0; 633 | }) 634 | 635 | 636 | it("should out 'declare' when this.depth === 0", ()=>{ 637 | 638 | 639 | const out = dg.addDeclare(); 640 | const answer = "declare "; 641 | assert.deepEqual(out, answer); 642 | }); 643 | 644 | }); 645 | 646 | context("resolveNamespace()", ()=>{ 647 | 648 | it("should resolve !ret containing path",()=>{ 649 | const path = "sinon.spy.reset.!ret.named.!ret"; 650 | 651 | const out = dg.resolveNamespace(path.split(".")); 652 | const ans = "sinon.spy.ResetRet"; 653 | 654 | assert.deepEqual(out, ans); 655 | 656 | }) 657 | 658 | it("should resolve !node containing path",()=>{ 659 | const path = "!node.``/node_modules/tern/lib/tern`js.Server.prototype.flush.!0"; 660 | const out = dg.resolveNamespace(path.split(".")); 661 | //dg.option.isOutExport = true; 662 | //dg.nodeModuleName = "``/node_modules/tern/lib/tern`js"; 663 | //dg.userDefinedModuleName = "tern"; 664 | const ans = "Server.prototype"; 665 | 666 | assert.deepEqual(out, ans); 667 | }); 668 | 669 | it("should resolve !node containing path with replacing",()=>{ 670 | const path = "!node.``/node_modules/tern/lib/tern`js.Server.prototype.flush.!0"; 671 | 672 | dg.option.isOutExport = true; 673 | dg["nodeModuleName"] = path.split(".")[1]; 674 | dg.userDefinedModuleName = "tern"; 675 | const out = dg.resolveNamespace(path.split(".")); 676 | const ans = "tern.Server.prototype"; 677 | 678 | //console.log("dg[nodeModuleName]:"+dg["nodeModuleName"]); 679 | 680 | assert.deepEqual(path.split(".")[1], dg.nodeModuleName); 681 | 682 | assert.deepEqual(out, ans); 683 | }); 684 | 685 | 686 | 687 | }); 688 | 689 | context("resolvePathToDTSName", ()=>{ 690 | 691 | it("should resolve DTSName", ()=>{ 692 | const path = "sinon.Event.prototype.initEvent.!3"; 693 | const out = dg.resolvePathToDTSName(path.split(".")); 694 | 695 | const ans = "InitEvent3"; 696 | 697 | assert.deepEqual(out, ans); 698 | 699 | }); 700 | 701 | it("should resolve tern def node only path DTSName",()=>{ 702 | 703 | const path = "!modules.node_modules/gulp-header/index`js.!1"; 704 | dg.nodeModuleName = "node_modules/gulp-header/index`js"; 705 | dg.option.isOutExport = true; 706 | dg.option.exportModuleName = "gulp-header"; 707 | dg.userDefinedModuleName = "gulpHeader"; 708 | const out = dg.resolvePathToDTSName(path.split(".")); 709 | const ans = "GulpHeader1"; 710 | 711 | assert.deepEqual(out, ans); 712 | 713 | }); 714 | 715 | }); 716 | 717 | }); -------------------------------------------------------------------------------- /test/example-test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'power-assert'; 2 | import * as sinon from 'sinon'; 3 | import {dtsmake} from '../src/dtsmake'; 4 | import * as fs from 'fs'; 5 | 6 | describe("Example js file tests", ()=>{ 7 | 8 | let dg:dtsmake.DTSMake; 9 | const dir = "./test/.tmp" 10 | beforeEach(()=>{ 11 | dg = new dtsmake.DTSMake(); 12 | 13 | if(!fs.existsSync(dir)){ 14 | fs.mkdirSync(dir) 15 | } 16 | }); 17 | 18 | 19 | 20 | 21 | context("infer.js test", ()=>{ 22 | it("condenced infer.js json file to d.ts file",()=>{ 23 | assert.ifError( 24 | dg.main( 25 | "./sample/infer.js.json", 26 | "./test/.tmp/infer", 27 | { 28 | isOutVoidAsAny:true, 29 | isOutExport:false, 30 | exportModuleName:"infer" 31 | } 32 | ) 33 | ); 34 | assert(dg.option.isAnnotateTypeInstance === true,"annotaion opition"); 35 | assert(dg.option.isOutVoidAsAny === true, "is out void as any"); 36 | }); 37 | }); 38 | 39 | context("tern.js test", ()=>{ 40 | it("condenced tern.js json file to d.ts file",()=>{ 41 | assert.ifError( 42 | dg.main( 43 | "./sample/tern.js.json", 44 | "./test/.tmp/tern" 45 | , 46 | { 47 | isNodeJsModule:true, 48 | isOutExport:true, 49 | exportModuleName:"tern/lib/tern", 50 | exportStyle:"legacy" 51 | } 52 | ) 53 | ); 54 | assert(dg.option.isAnnotateTypeInstance === true,"annotaion opition"); 55 | assert(dg.option.isOutVoidAsAny === false, "is out void as any"); 56 | }); 57 | }); 58 | 59 | }); -------------------------------------------------------------------------------- /test/file-test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'power-assert'; 2 | import * as sinon from 'sinon'; 3 | import {dtsmake} from '../src/dtsmake'; 4 | import * as fs from 'fs'; 5 | 6 | describe("File manipulation tests", ()=>{ 7 | let dg = new dtsmake.DTSMake(); 8 | 9 | context("load a JSON file", ()=>{ 10 | 11 | it("should load a real json file",(done)=>{ 12 | dg.loadTernJson("sample/infer.js.json",(data:JSON)=>{ 13 | //assert.ifError(data); 14 | assert(data, "data is null/undefined"); 15 | done(); 16 | }); 17 | }); 18 | 19 | 20 | }); 21 | 22 | context.skip("save a JSON file",()=>{ 23 | let realFile:JSON; 24 | beforeEach((done)=>{ 25 | dg.option.isOutVoidAsAny = false; 26 | dg.loadTernJson("sample/infer.js.json",(data:JSON)=>{ 27 | realFile = data; 28 | done(); 29 | }); 30 | }); 31 | 32 | it("should save dummy data json file.",(done)=>{ 33 | dg.saveJSON("test/.tmp/test.json", JSON.stringify({hoge:"guga",n:0,hi:[0,1,3]}), ()=>{ 34 | done(); 35 | }); 36 | }); 37 | 38 | 39 | 40 | it("should save real data json file.",(done)=>{ 41 | dg.saveJSON("test/.tmp/infer.json", JSON.stringify(realFile), ()=>{ 42 | assert(realFile); 43 | done(); 44 | }); 45 | }); 46 | }); 47 | 48 | context("saveTSDFile()",()=>{ 49 | 50 | 51 | 52 | let fileData = 53 | ` 54 | interface Hoge{ 55 | new (): Hoge; 56 | prop: number; 57 | addHoge(param:string): Hoge; 58 | } 59 | declare var Hoge:Hoge; 60 | `; 61 | it("should return true when save complate",(done)=>{ 62 | 63 | assert(dg.saveTSDFile("test/.tmp/test",fileData)); 64 | //this.timeout(30000); 65 | done(); 66 | }); 67 | }); 68 | }); -------------------------------------------------------------------------------- /test/parse-test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'power-assert'; 2 | import {dtsmake} from '../src/dtsmake'; 3 | import fs = require('fs'); 4 | 5 | describe("Parsing TernJS definition JSON file(s), ",()=>{ 6 | let dg = new dtsmake.DTSMake(); 7 | 8 | 9 | 10 | context("parseToDTS()", ()=>{ 11 | 12 | 13 | it.skip("should parse !type type to DTS",()=>{ 14 | 15 | let baseDef = { 16 | "Fn": { 17 | "!type": "fn(name: string, self: +tern.AVal, args: [?], argNames: [string], retval: ?)", 18 | "name": "string", 19 | "test": "?" 20 | } 21 | }; 22 | 23 | let parsedJson = dg.parseJsonNodeDTS(baseDef); 24 | 25 | let out = dg.parseToDTS(parsedJson); 26 | const answer3 = `"Fn":{"new ":{}}`; 27 | assert.deepEqual( 28 | out,answer3, 29 | `out string ${out} is not match answer str ${answer3}.` 30 | ); 31 | 32 | }); 33 | 34 | 35 | 36 | }); 37 | 38 | context("replaceExportNamespace()",()=>{ 39 | 40 | it("should replace module name when isOutExport ON",()=>{ 41 | 42 | const def = { 43 | [dtsmake.TernDef.NAME]:"TEST_NAME", 44 | [dtsmake.TernDef.DEFINE]:{ 45 | [dtsmake.TernDef.NODE]:{ 46 | "node_modules/path/to/module`js":{ 47 | "prop":{ 48 | type:dtsmake.TSObjType.BOOLEAN 49 | } 50 | } 51 | } 52 | } 53 | }; 54 | 55 | dg.option.isOutExport = true; 56 | dg.nodeModuleName = "node_modules/path/to/module`js"; 57 | dg.userDefinedModuleName = "TEST_NAME"; 58 | 59 | let out = dg.replaceExportNamespace(def); 60 | //console.log(JSON.stringify(out)) 61 | let answer = { 62 | [dtsmake.TernDef.NAME]:"TEST_NAME", 63 | [dtsmake.TernDef.DEFINE]:{ 64 | [dtsmake.TernDef.NODE]:{ 65 | [dg.userDefinedModuleName]:{ 66 | "prop":{ 67 | type:dtsmake.TSObjType.BOOLEAN 68 | } 69 | } 70 | } 71 | } 72 | }; 73 | 74 | assert.deepEqual(out, answer); 75 | 76 | 77 | }); 78 | 79 | }); 80 | 81 | context("parseJsonNodeDTS()",()=>{ 82 | it("should be output !type param array type",()=>{ 83 | 84 | const def = { 85 | "Fn":{ 86 | "!type": "fn(sParams: [string], nParams: [number])" 87 | } 88 | }; 89 | 90 | let out = dg.parseJsonNodeDTS(def); 91 | let answer = { 92 | "Fn":{ 93 | "!type":[ 94 | {"type":dtsmake.TSObjType.FUNCTION, 95 | "params":[ 96 | { 97 | "type":dtsmake.TSObjType.ARRAY, 98 | "arrayType": [ 99 | {"type":dtsmake.TSObjType.STRING} 100 | ], 101 | "name":"sParams" 102 | }, 103 | { 104 | "type":dtsmake.TSObjType.ARRAY, 105 | "arrayType": [ 106 | {"type":dtsmake.TSObjType.NUMBER} 107 | ], 108 | "name":"nParams" 109 | } 110 | ], 111 | "ret":[ 112 | { 113 | "type":dtsmake.TSObjType.VOID 114 | } 115 | ] 116 | } 117 | ] 118 | 119 | } 120 | } 121 | assert.deepEqual( 122 | out,answer, 123 | `out ${JSON.stringify(out)}\n, answer ${JSON.stringify(answer)}` 124 | ) 125 | 126 | 127 | }); 128 | 129 | 130 | it.skip("should be output !proto collectly",()=>{ 131 | const def = { 132 | "Fn":{ 133 | "!type":"fn()", 134 | "prototype":{ 135 | "!proto": "tern.Obj.prototype" 136 | } 137 | } 138 | }; 139 | const out = dg.parseJsonNodeDTS(def); 140 | const answer = { 141 | "Fn":{} 142 | }; 143 | assert.deepEqual( 144 | out, answer 145 | ); 146 | 147 | }); 148 | 149 | }) 150 | 151 | context("parseTernDef()",()=>{ 152 | 153 | it("should parse simple array",()=>{ 154 | const def = "[string]"; 155 | const answer = [ 156 | { 157 | "type":dtsmake.TSObjType.ARRAY, 158 | //"name":"test", 159 | "arrayType": [ 160 | {"type":dtsmake.TSObjType.STRING} 161 | ] 162 | } 163 | ]; 164 | 165 | let out = dg.parseTernDef(def); 166 | assert.deepEqual( 167 | out, answer, 168 | `out ${JSON.stringify(out)},\n`+ 169 | `ans ${JSON.stringify(answer)}` 170 | ); 171 | }); 172 | 173 | it("should parse single array param fn",()=>{ 174 | const def = "fn(p1: [string])"; 175 | const answer = 176 | [ 177 | { 178 | "type":dtsmake.TSObjType.FUNCTION, 179 | "ret":[ 180 | { 181 | "type":dtsmake.TSObjType.VOID 182 | } 183 | ], 184 | "params":[ 185 | { 186 | "type":dtsmake.TSObjType.ARRAY, 187 | "name":"p1", 188 | "arrayType": [ 189 | {"type":dtsmake.TSObjType.STRING} 190 | ] 191 | } 192 | ] 193 | } 194 | ]; 195 | 196 | let out = dg.parseTernDef(def); 197 | assert.deepEqual( 198 | out, answer, 199 | `out ${JSON.stringify(out)},\n`+ 200 | `ans ${JSON.stringify(answer)}` 201 | ); 202 | }); 203 | 204 | it("should parse optional param fn",()=>{ 205 | const def = "fn(p1?: [string])"; 206 | const answer = 207 | [ 208 | { 209 | "type":dtsmake.TSObjType.FUNCTION, 210 | "ret":[ 211 | { 212 | "type":dtsmake.TSObjType.VOID 213 | } 214 | ], 215 | "params":[ 216 | { 217 | "type":dtsmake.TSObjType.ARRAY, 218 | "name":"p1?", 219 | "arrayType": [ 220 | {"type":dtsmake.TSObjType.STRING} 221 | ] 222 | } 223 | ] 224 | } 225 | ]; 226 | 227 | let out = dg.parseTernDef(def); 228 | assert.deepEqual( 229 | out, answer, 230 | `out ${JSON.stringify(out)},\n`+ 231 | `ans ${JSON.stringify(answer)}` 232 | ); 233 | }); 234 | 235 | it("should parse double array params fn",()=>{ 236 | const def = "fn(sParams: [string], nParams: [number])"; 237 | const answer = [ 238 | {"type":dtsmake.TSObjType.FUNCTION, 239 | "ret":[ 240 | { 241 | "type":dtsmake.TSObjType.VOID 242 | } 243 | ], 244 | "params":[ 245 | { 246 | "type":dtsmake.TSObjType.ARRAY, 247 | "arrayType": [ 248 | {"type":dtsmake.TSObjType.STRING} 249 | ], 250 | "name":"sParams" 251 | }, 252 | { 253 | "type":dtsmake.TSObjType.ARRAY, 254 | "arrayType": [ 255 | {"type":dtsmake.TSObjType.NUMBER} 256 | ], 257 | "name":"nParams" 258 | } 259 | ] 260 | } 261 | ]; 262 | let out = dg.parseTernDef(def); 263 | assert.deepEqual(out,answer, `\ndef out ${JSON.stringify(out)},\nanswer ${JSON.stringify(answer)}`); 264 | 265 | }); 266 | 267 | //it("should parse ") 268 | 269 | it("should parse union params fn",()=>{ 270 | const def = "fn(a: string|number)"; 271 | const answer = [ 272 | {"type":dtsmake.TSObjType.FUNCTION, 273 | "ret":[ 274 | { 275 | "type":dtsmake.TSObjType.VOID 276 | } 277 | ], 278 | "params":[ 279 | [ 280 | { 281 | "name":"a", 282 | "type":dtsmake.TSObjType.STRING 283 | }, 284 | { 285 | "name":"a", 286 | "type":dtsmake.TSObjType.NUMBER 287 | } 288 | ] 289 | ] 290 | } 291 | ]; 292 | let out = dg.parseTernDef(def); 293 | assert.deepEqual(out, answer); 294 | }); 295 | 296 | it("should parse fn union params fn",()=>{ 297 | const def = "fn(a: fn(string)|fn(number))"; 298 | const answer = [ 299 | {"type":dtsmake.TSObjType.FUNCTION, 300 | "ret":[ 301 | { 302 | "type":dtsmake.TSObjType.VOID 303 | } 304 | ], 305 | "params":[ 306 | [ 307 | { 308 | "name":"a", 309 | "params":[{ 310 | "type":dtsmake.TSObjType.STRING 311 | }], 312 | "type":dtsmake.TSObjType.FUNCTION, 313 | "ret":[{ 314 | "type":dtsmake.TSObjType.VOID 315 | }] 316 | }, 317 | { 318 | "name":"a", 319 | "params":[{ 320 | "type":dtsmake.TSObjType.NUMBER 321 | }], 322 | "type":dtsmake.TSObjType.FUNCTION, 323 | "ret":[{ 324 | "type":dtsmake.TSObjType.VOID 325 | }] 326 | } 327 | ] 328 | ] 329 | } 330 | ]; 331 | let out = dg.parseTernDef(def); 332 | assert.deepEqual(out, answer); 333 | }); 334 | }); 335 | 336 | context("parseParams()",()=>{ 337 | it("should parse fn params array",()=>{ 338 | const def = "fn(sParams:[string],nParams:[number])"; 339 | const answer = 340 | [ 341 | { 342 | "type":dtsmake.TSObjType.ARRAY, 343 | "arrayType": [ 344 | {"type":dtsmake.TSObjType.STRING} 345 | ], 346 | "name":"sParams" 347 | }, 348 | { 349 | "type":dtsmake.TSObjType.ARRAY, 350 | "arrayType": [ 351 | {"type":dtsmake.TSObjType.NUMBER} 352 | ], 353 | "name":"nParams" 354 | } 355 | ]; 356 | 357 | let out = dg.parseParams(def); 358 | assert.deepEqual(out,answer, `\ndef out ${JSON.stringify(out)},\nanswer ${JSON.stringify(answer)}`); 359 | 360 | }); 361 | 362 | it("should parse fn union params", ()=>{ 363 | const def = "fn(a: fn(string)|fn(number))"; 364 | const answer = [ 365 | [ 366 | { 367 | "name":"a", 368 | "params":[{ 369 | "type":dtsmake.TSObjType.STRING 370 | }], 371 | "type":dtsmake.TSObjType.FUNCTION, 372 | "ret":[{ 373 | "type":dtsmake.TSObjType.VOID 374 | }] 375 | }, 376 | { 377 | "name":"a", 378 | "params":[{ 379 | "type":dtsmake.TSObjType.NUMBER 380 | }], 381 | "type":dtsmake.TSObjType.FUNCTION, 382 | "ret":[{ 383 | "type":dtsmake.TSObjType.VOID 384 | }] 385 | } 386 | ] 387 | ]; 388 | let out = dg.parseParams(def); 389 | assert.deepEqual(out, answer); 390 | }); 391 | 392 | }); 393 | 394 | context("splitParams()",()=>{ 395 | it("should parse fn params array",()=>{ 396 | const def = "sParams:[string],nParams:[number]"; 397 | const answer = 398 | [ 399 | "sParams:[string]", 400 | "nParams:[number]" 401 | ]; 402 | 403 | let out = dg.splitParams(def); 404 | assert.deepEqual(out,answer, `\ndef out ${JSON.stringify(out)},\nanswer ${JSON.stringify(answer)}`); 405 | 406 | }); 407 | 408 | }); 409 | 410 | 411 | context("parseTernJson()",()=>{ 412 | let loadData:JSON; 413 | beforeEach((done)=>{ 414 | 415 | dg.loadTernJson("sample/infer.js.json",(jsonData)=>{ 416 | loadData = jsonData; 417 | done(); 418 | }) 419 | 420 | 421 | 422 | }); 423 | 424 | let nodeDTSObj:any; 425 | it("parseJsonNodeDTS()",(done)=>{ 426 | nodeDTSObj = dg.parseJsonNodeDTS(loadData); 427 | 428 | done(); 429 | }); 430 | 431 | let modifiedObj; 432 | it("preModifiedJson()", (done)=>{ 433 | modifiedObj = dg.preModifiedJson(nodeDTSObj); 434 | done(); 435 | }); 436 | }); 437 | 438 | context("Type checking ternjs type strings",()=>{ 439 | 440 | const s = 441 | [ 442 | {type:dtsmake.TSObjType.ANY, str:"?"}, 443 | {type:dtsmake.TSObjType.ARRAY, str:"[number]"}, 444 | {type:dtsmake.TSObjType.BOOLEAN, str:"bool"}, 445 | {type:dtsmake.TSObjType.CLASS, str:"+hoge.fuga.Class"}, 446 | {type:dtsmake.TSObjType.FUNCTION, str:"fn(?,?)->?"}, 447 | {type:dtsmake.TSObjType.NUMBER, str:"number"}, 448 | {type:dtsmake.TSObjType.OBJECT, str:"hoge"}, 449 | {type:dtsmake.TSObjType.STRING, str:"string"}, 450 | {type:dtsmake.TSObjType.UNIONS, str:"number|string"} 451 | ]; 452 | 453 | it("basic type check",()=>{ 454 | for(let i in s){ 455 | let o = s[i]; 456 | assert(dg.checkType(o.str) === o.type,`type ${dtsmake.TSObjType[o.type]} check faild.`); 457 | } 458 | }); 459 | 460 | const objs = 461 | [ 462 | {type:dtsmake.TSObjType.OBJECT, str:"!this"}, 463 | {type:dtsmake.TSObjType.OBJECT, str:"!this.Obj"}, 464 | {type:dtsmake.TSObjType.OBJECT, str:"some.namespace.to.object"}, 465 | {type:dtsmake.TSObjType.OBJECT, str:"!ternjs.!internal.!refs.!0."} 466 | ]; 467 | const noObjs = 468 | [ 469 | "number", 470 | "string", 471 | "+hoge.fuga", 472 | "bool", 473 | "?", 474 | "?|bool", 475 | "fn(number|?,bool|?)->+hoge.fuga", 476 | "[bool|number]", 477 | "[+hoge.fuga]" 478 | ]; 479 | 480 | it("object type check",()=>{ 481 | for(let i in objs){ 482 | let o = objs[i]; 483 | assert(dg.checkType(o.str) === o.type,`type ${dtsmake.TSObjType[o.type]} check faild.`); 484 | } 485 | 486 | for(let i in noObjs){ 487 | let o = noObjs[i]; 488 | assert(dg.checkType(o) !== dtsmake.TSObjType.OBJECT,`${o} is may object.`); 489 | } 490 | }); 491 | 492 | 493 | /* 494 | const mems = [ 495 | {type:dtsmake.TSObjType.OBJ_MEMBER, str:"!this"}, 496 | {type:dtsmake.TSObjType.OBJ_MEMBER, str:"!this.member"}, 497 | {type:dtsmake.TSObjType.OBJ_MEMBER, str:"!this.member.child.child"}, 498 | {type:dtsmake.TSObjType.OBJ_MEMBER, str:"!this.member.!this.!this.!node"} 499 | ]; 500 | it("this member obj check",()=>{ 501 | for(let i in mems){ 502 | let o = mems[i]; 503 | assert(dg.checkType(o.str) === o.type,`type ${dtsmake.TSObjType[o.type]} check faild.`); 504 | } 505 | }); 506 | */ 507 | 508 | }); 509 | 510 | context("checkReplaceTypes(), ", ()=>{ 511 | 512 | it("should match replace fn return type",()=>{ 513 | let path = ["Klass", "prototype", "prop", "!ret"]; 514 | let t = dg.checkReplaceType(path[path.length-1]); 515 | 516 | assert(t == dtsmake.ReplaceType.RETURN, 517 | `${path[path.length-1]} is not match ReplaceType.RETURN` 518 | ); 519 | }); 520 | 521 | it("should match may be Class",()=>{ 522 | let cs = [ 523 | "A", 524 | "Ab", 525 | "Abc", 526 | "ABC", 527 | "KlassA" 528 | ]; 529 | for(let i in cs){ 530 | assert( 531 | dg.checkReplaceType(cs[i]) === dtsmake.ReplaceType.CLASS, 532 | `${cs[i]} may not be Class` 533 | ); 534 | } 535 | }); 536 | 537 | it("should match array type",()=>{ 538 | let cs = [ 539 | "", 540 | "", 541 | "", 542 | "", 543 | "" 544 | ]; 545 | for(let i in cs){ 546 | let out = dg.checkReplaceType(cs[i]); 547 | assert( 548 | out === dtsmake.ReplaceType.ARRAY, 549 | `${cs[i]} may not be Array` 550 | ); 551 | } 552 | }) 553 | }); 554 | 555 | 556 | context("search ternjs ref & replace dts ref, ",()=>{ 557 | 558 | let test = { 559 | "!define":{ 560 | "Klass.prop.!ret":[ 561 | { 562 | "type": dtsmake.TSObjType.CLASS, 563 | "class":"+Klass" 564 | } 565 | ] 566 | }, 567 | "Klass":{ 568 | "prop":{ 569 | "type":dtsmake.TSObjType.FUNCTION, 570 | "ret":[ 571 | { 572 | "type": dtsmake.TSObjType.OBJECT, 573 | "class": "!this" 574 | } 575 | ], 576 | "params": null 577 | }, 578 | "prop2":{ 579 | "type":dtsmake.TSObjType.NUMBER 580 | } 581 | } 582 | }; 583 | 584 | beforeEach(()=>{ 585 | test = { 586 | "!define":{ 587 | "Klass.prop.!ret":[ 588 | { 589 | "type": dtsmake.TSObjType.CLASS, 590 | "class":"+Klass" 591 | } 592 | ] 593 | }, 594 | "Klass":{ 595 | "prop":{ 596 | "type":dtsmake.TSObjType.FUNCTION, 597 | "ret":[ 598 | { 599 | "type": dtsmake.TSObjType.OBJECT, 600 | "class": "!this" 601 | } 602 | ], 603 | "params": null 604 | }, 605 | "prop2":{ 606 | "type":dtsmake.TSObjType.NUMBER 607 | } 608 | } 609 | }; 610 | }); 611 | 612 | it("should search prototype ref (Klass.prototype.prop.!ret)", ()=>{ 613 | let ref = dg.searchRef( 614 | test, 615 | ["Klass","prototype","prop","!ret"], 616 | false 617 | ); 618 | assert(ref, "no ref"); 619 | }); 620 | 621 | it("should search prototype prop ref", ()=>{ 622 | let ref2 = dg.searchRef( 623 | test, 624 | ["Klass","prototype","prop2"], 625 | false 626 | ); 627 | assert(ref2, "no ref"); 628 | }); 629 | 630 | it("should faild search non ref", ()=>{ 631 | let ref = dg.searchRef( 632 | test, 633 | ["Klass","hoge","fuga","!0"], 634 | false 635 | ); 636 | assert(!ref, "no ref should be no ref"); 637 | }); 638 | 639 | 640 | 641 | it("should replace prototype ref to Class ref", ()=>{ 642 | dg.searchAndReplaceDTS( 643 | test, 644 | ["Klass","prototype","prop"], 645 | "PropRet", 646 | false 647 | ); 648 | //console.log(JSON.stringify(test)); 649 | }); 650 | 651 | it("should replace prototype ref to Class ref 2", ()=>{ 652 | dg.searchAndReplaceDTS( 653 | test, 654 | ["Klass","prototype","prop2"], 655 | "Prop2", 656 | false 657 | ); 658 | 659 | }); 660 | 661 | it.skip("should replace local !ret", ()=>{ 662 | 663 | const o = { 664 | "scopeAt": { 665 | "!type": [ 666 | { 667 | "type": 5, 668 | "ret": [ 669 | { 670 | "type": 9, 671 | "class": "!2" 672 | } 673 | ], 674 | "params": [ 675 | { 676 | "name": "ast", 677 | "type": 0 678 | }, 679 | { 680 | "name": "pos", 681 | "type": 0 682 | }, 683 | { 684 | "name": "defaultScope", 685 | "type": 0 686 | } 687 | ] 688 | } 689 | ] 690 | } 691 | }; 692 | const answer = { 693 | "scopeAt": { 694 | //"!type": "fn(ast: ?, pos: ?, defaultScope: ?) -> !2" 695 | "!type":[{ 696 | "type":dtsmake.TSObjType.FUNCTION, 697 | "params":[ 698 | { 699 | "type":dtsmake.TSObjType.ANY, 700 | "name":"ast" 701 | }, 702 | { 703 | "type":dtsmake.TSObjType.ANY, 704 | "name":"pos" 705 | }, 706 | { 707 | "type":dtsmake.TSObjType.ANY, 708 | "name":"defaultScope" 709 | } 710 | ], 711 | "ret":[ 712 | { 713 | "type":dtsmake.TSObjType.ANY, 714 | "class":"!2" 715 | } 716 | ] 717 | }] 718 | } 719 | }; 720 | let out = dg.searchRef(o,["!2"],false); 721 | console.log("ref", JSON.stringify(out)); 722 | dg.searchAndReplaceDTS(o, ["!ret"],"",false); 723 | 724 | assert.deepEqual(o, answer); 725 | 726 | }); 727 | 728 | }); 729 | 730 | 731 | context("preModifiedJson()", ()=>{ 732 | let def:{}; 733 | 734 | beforeEach(()=>{ 735 | 736 | def = { 737 | "Math":{ 738 | "prop":{ 739 | type:dtsmake.TSObjType.STRING 740 | } 741 | }, 742 | "NoGlobal":{} 743 | }; 744 | 745 | dg["userDefinedModuleName"] = "MyLib"; 746 | 747 | }); 748 | 749 | 750 | it("should remove a object that same name with JS Global Object",()=>{ 751 | 752 | dg.option.globalObject = dtsmake.Option.GlobalObject.REMOVE; 753 | let out = dg.preModifiedJson(def); 754 | let answer = { 755 | "NoGlobal":{} 756 | }; 757 | 758 | assert.deepEqual(out, answer); 759 | 760 | }); 761 | 762 | it("should wrap a object that same name with JS Global Object",()=>{ 763 | 764 | dg.option.globalObject = dtsmake.Option.GlobalObject.WRAP; 765 | 766 | let out = dg.preModifiedJson(def); 767 | let answer = { 768 | "MyLib":{ 769 | "Math":{ 770 | "prop":{ 771 | type:dtsmake.TSObjType.STRING 772 | }, 773 | "!!!dtsinterface!!!":"Math" 774 | } 775 | }, 776 | "NoGlobal":{} 777 | }; 778 | 779 | assert.deepEqual(out, answer); 780 | 781 | }); 782 | 783 | it("should rename a object that same name with JS Global Object",()=>{ 784 | 785 | dg.option.globalObject = dtsmake.Option.GlobalObject.RENAME; 786 | 787 | let out = dg.preModifiedJson(def); 788 | let answer = { 789 | "MyLib$Math":{ 790 | "prop":{ 791 | type:dtsmake.TSObjType.STRING 792 | } 793 | }, 794 | "NoGlobal":{} 795 | }; 796 | 797 | assert.deepEqual(out, answer); 798 | 799 | }); 800 | 801 | it.skip("should rename & extend a object that same name with JS Global Object",()=>{ 802 | 803 | dg.option.globalObject = dtsmake.Option.GlobalObject.RENAME; 804 | 805 | let out = dg.preModifiedJson(def); 806 | let answer = { 807 | "MyLib$Math":{ 808 | "prop":{ 809 | type:dtsmake.TSObjType.STRING 810 | }, 811 | "!proto":{ 812 | type:dtsmake.TSObjType.CLASS, 813 | class:"Math.prototype" 814 | } 815 | }, 816 | "NoGlobal":{} 817 | }; 818 | 819 | assert.deepEqual(out, answer); 820 | 821 | }); 822 | }); 823 | 824 | }); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "noImplicitAny": true, 5 | "suppressImplicitAnyIndexErrors": true, 6 | "removeComments": false, 7 | "preserveConstEnums": false, 8 | "noEmitOnError": true, 9 | //"strictNullChecks": true, 10 | //"noResolve":true, 11 | "pretty": true, 12 | "target": "es5", 13 | "lib": [ 14 | "es2015" 15 | ], 16 | "outDir": "lib", 17 | "newLine": "LF" 18 | //, 19 | //"rootDir": "src" 20 | }, 21 | "include":[ 22 | "src/index.ts", 23 | "node_modules/@types/*/*.d.ts" 24 | ], 25 | "exclude": [ 26 | "gulpfile.ts" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /typings/clone/clone.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for clone 0.1.11 2 | // Project: https://github.com/pvorb/node-clone 3 | // Definitions by: Kieran Simpson 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /** 7 | * See clone JS source for API docs 8 | */ 9 | declare module "clone" { 10 | /** 11 | * @param val the value that you want to clone, any type allowed 12 | * @param circular Call clone with circular set to false if you are certain that obj contains no circular references. This will give better performance if needed. There is no error if undefined or null is passed as obj. 13 | * @param depth to wich the object is to be cloned (optional, defaults to infinity) 14 | */ 15 | function clone(val: T, circular?: boolean, depth?: number): T; 16 | 17 | module clone { 18 | /** 19 | * @param obj the object that you want to clone 20 | */ 21 | function clonePrototype(obj: T): T; 22 | } 23 | 24 | export = clone 25 | } 26 | -------------------------------------------------------------------------------- /typings/empower/empower.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for empower 2 | // Project: https://github.com/twada/empower 3 | // Definitions by: vvakame 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | declare function empower(originalAssert:any, formatter:any, options?:empower.Options):any; 7 | 8 | declare module empower { 9 | export interface Options { 10 | destructive?: boolean; 11 | modifyMessageOnRethrow?: boolean; 12 | saveContextOnRethrow?: boolean; 13 | patterns?: string[]; 14 | } 15 | } 16 | 17 | declare module "empower" { 18 | export = empower; 19 | } 20 | -------------------------------------------------------------------------------- /typings/mocha/mocha.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for mocha 2.2.5 2 | // Project: http://mochajs.org/ 3 | // Definitions by: Kazi Manzur Rashid , otiai10 , jt000 , Vadim Macagon 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | interface MochaSetupOptions { 7 | //milliseconds to wait before considering a test slow 8 | slow?: number; 9 | 10 | // timeout in milliseconds 11 | timeout?: number; 12 | 13 | // ui name "bdd", "tdd", "exports" etc 14 | ui?: string; 15 | 16 | //array of accepted globals 17 | globals?: any[]; 18 | 19 | // reporter instance (function or string), defaults to `mocha.reporters.Spec` 20 | reporter?: any; 21 | 22 | // bail on the first test failure 23 | bail?: boolean; 24 | 25 | // ignore global leaks 26 | ignoreLeaks?: boolean; 27 | 28 | // grep string or regexp to filter tests with 29 | grep?: any; 30 | } 31 | 32 | interface MochaDone { 33 | (error?: Error): void; 34 | } 35 | 36 | declare var mocha: Mocha; 37 | declare var describe: Mocha.IContextDefinition; 38 | declare var xdescribe: Mocha.IContextDefinition; 39 | // alias for `describe` 40 | declare var context: Mocha.IContextDefinition; 41 | // alias for `describe` 42 | declare var suite: Mocha.IContextDefinition; 43 | declare var it: Mocha.ITestDefinition; 44 | declare var xit: Mocha.ITestDefinition; 45 | // alias for `it` 46 | declare var test: Mocha.ITestDefinition; 47 | 48 | declare function before(action: () => void): void; 49 | 50 | declare function before(action: (done: MochaDone) => void): void; 51 | 52 | declare function setup(action: () => void): void; 53 | 54 | declare function setup(action: (done: MochaDone) => void): void; 55 | 56 | declare function after(action: () => void): void; 57 | 58 | declare function after(action: (done: MochaDone) => void): void; 59 | 60 | declare function teardown(action: () => void): void; 61 | 62 | declare function teardown(action: (done: MochaDone) => void): void; 63 | 64 | declare function beforeEach(action: () => void): void; 65 | 66 | declare function beforeEach(action: (done: MochaDone) => void): void; 67 | 68 | declare function suiteSetup(action: () => void): void; 69 | 70 | declare function suiteSetup(action: (done: MochaDone) => void): void; 71 | 72 | declare function afterEach(action: () => void): void; 73 | 74 | declare function afterEach(action: (done: MochaDone) => void): void; 75 | 76 | declare function suiteTeardown(action: () => void): void; 77 | 78 | declare function suiteTeardown(action: (done: MochaDone) => void): void; 79 | 80 | declare class Mocha { 81 | constructor(options?: { 82 | grep?: RegExp; 83 | ui?: string; 84 | reporter?: string; 85 | timeout?: number; 86 | bail?: boolean; 87 | }); 88 | 89 | /** Setup mocha with the given options. */ 90 | setup(options: MochaSetupOptions): Mocha; 91 | bail(value?: boolean): Mocha; 92 | addFile(file: string): Mocha; 93 | /** Sets reporter by name, defaults to "spec". */ 94 | reporter(name: string): Mocha; 95 | /** Sets reporter constructor, defaults to mocha.reporters.Spec. */ 96 | reporter(reporter: (runner: Mocha.IRunner, options: any) => any): Mocha; 97 | ui(value: string): Mocha; 98 | grep(value: string): Mocha; 99 | grep(value: RegExp): Mocha; 100 | invert(): Mocha; 101 | ignoreLeaks(value: boolean): Mocha; 102 | checkLeaks(): Mocha; 103 | /** Enables growl support. */ 104 | growl(): Mocha; 105 | globals(value: string): Mocha; 106 | globals(values: string[]): Mocha; 107 | useColors(value: boolean): Mocha; 108 | useInlineDiffs(value: boolean): Mocha; 109 | timeout(value: number): Mocha; 110 | slow(value: number): Mocha; 111 | enableTimeouts(value: boolean): Mocha; 112 | asyncOnly(value: boolean): Mocha; 113 | noHighlighting(value: boolean): Mocha; 114 | /** Runs tests and invokes `onComplete()` when finished. */ 115 | run(onComplete?: (failures: number) => void): Mocha.IRunner; 116 | } 117 | 118 | // merge the Mocha class declaration with a module 119 | declare module Mocha { 120 | /** Partial interface for Mocha's `Runnable` class. */ 121 | interface IRunnable { 122 | title: string; 123 | fn: Function; 124 | async: boolean; 125 | sync: boolean; 126 | timedOut: boolean; 127 | } 128 | 129 | /** Partial interface for Mocha's `Suite` class. */ 130 | interface ISuite { 131 | parent: ISuite; 132 | title: string; 133 | 134 | fullTitle(): string; 135 | } 136 | 137 | /** Partial interface for Mocha's `Test` class. */ 138 | interface ITest extends IRunnable { 139 | parent: ISuite; 140 | pending: boolean; 141 | 142 | fullTitle(): string; 143 | } 144 | 145 | /** Partial interface for Mocha's `Runner` class. */ 146 | interface IRunner {} 147 | 148 | interface IContextDefinition { 149 | (description: string, spec: () => void): ISuite; 150 | only(description: string, spec: () => void): ISuite; 151 | skip(description: string, spec: () => void): void; 152 | timeout(ms: number): void; 153 | } 154 | 155 | interface ITestDefinition { 156 | (expectation: string, assertion?: () => void): ITest; 157 | (expectation: string, assertion?: (done: MochaDone) => void): ITest; 158 | only(expectation: string, assertion?: () => void): ITest; 159 | only(expectation: string, assertion?: (done: MochaDone) => void): ITest; 160 | skip(expectation: string, assertion?: () => void): void; 161 | skip(expectation: string, assertion?: (done: MochaDone) => void): void; 162 | timeout(ms: number): void; 163 | } 164 | 165 | export module reporters { 166 | export class Base { 167 | stats: { 168 | suites: number; 169 | tests: number; 170 | passes: number; 171 | pending: number; 172 | failures: number; 173 | }; 174 | 175 | constructor(runner: IRunner); 176 | } 177 | 178 | export class Doc extends Base {} 179 | export class Dot extends Base {} 180 | export class HTML extends Base {} 181 | export class HTMLCov extends Base {} 182 | export class JSON extends Base {} 183 | export class JSONCov extends Base {} 184 | export class JSONStream extends Base {} 185 | export class Landing extends Base {} 186 | export class List extends Base {} 187 | export class Markdown extends Base {} 188 | export class Min extends Base {} 189 | export class Nyan extends Base {} 190 | export class Progress extends Base { 191 | /** 192 | * @param options.open String used to indicate the start of the progress bar. 193 | * @param options.complete String used to indicate a complete test on the progress bar. 194 | * @param options.incomplete String used to indicate an incomplete test on the progress bar. 195 | * @param options.close String used to indicate the end of the progress bar. 196 | */ 197 | constructor(runner: IRunner, options?: { 198 | open?: string; 199 | complete?: string; 200 | incomplete?: string; 201 | close?: string; 202 | }); 203 | } 204 | export class Spec extends Base {} 205 | export class TAP extends Base {} 206 | export class XUnit extends Base { 207 | constructor(runner: IRunner, options?: any); 208 | } 209 | } 210 | } 211 | 212 | declare module "mocha" { 213 | export = Mocha; 214 | } 215 | -------------------------------------------------------------------------------- /typings/power-assert-formatter/power-assert-formatter.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for power-assert-formatter 2 | // Project: https://github.com/twada/power-assert-formatter 3 | // Definitions by: vvakame 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | declare function powerAssertFormatter(options?:powerAssertFormatter.Options):powerAssertFormatter.Formatter; 7 | 8 | declare module powerAssertFormatter { 9 | export interface Options { 10 | lineDiffThreshold?: number; 11 | maxDepth?: number; 12 | outputOffset?: number; 13 | anonymous?: string; 14 | circular?: string; 15 | lineSeparator?: string; 16 | ambiguousEastAsianCharWidth?: number; 17 | widthOf?: Function; 18 | stringify?: Function; 19 | diff?: Function; 20 | writerClass?: {new (): any;}; 21 | renderers?: any[]; // { string | Function }[] 22 | } 23 | 24 | export interface Formatter { 25 | (powerAssertContext:any): string; 26 | } 27 | 28 | export function defaultOptions():Options; 29 | } 30 | -------------------------------------------------------------------------------- /typings/power-assert/power-assert.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for power-assert 2 | // Project: https://github.com/twada/power-assert 3 | // Definitions by: vvakame 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | // copy from assert external module in node.d.ts 7 | 8 | /// 9 | /// 10 | 11 | declare function assert(value:any, message?:string):void; 12 | declare module assert { 13 | export class AssertionError implements Error { 14 | name:string; 15 | message:string; 16 | actual:any; 17 | expected:any; 18 | operator:string; 19 | generatedMessage:boolean; 20 | 21 | constructor(options?:{message?: string; actual?: any; expected?: any; operator?: string; stackStartFunction?: Function}); 22 | } 23 | 24 | export function fail(actual?:any, expected?:any, message?:string, operator?:string):void; 25 | 26 | export function ok(value:any, message?:string):void; 27 | 28 | export function equal(actual:any, expected:any, message?:string):void; 29 | 30 | export function notEqual(actual:any, expected:any, message?:string):void; 31 | 32 | export function deepEqual(actual:any, expected:any, message?:string):void; 33 | 34 | export function notDeepEqual(acutal:any, expected:any, message?:string):void; 35 | 36 | export function strictEqual(actual:any, expected:any, message?:string):void; 37 | 38 | export function notStrictEqual(actual:any, expected:any, message?:string):void; 39 | 40 | export var throws:{ 41 | (block:Function, message?:string): void; 42 | (block:Function, error:Function, message?:string): void; 43 | (block:Function, error:RegExp, message?:string): void; 44 | (block:Function, error:(err:any) => boolean, message?:string): void; 45 | }; 46 | 47 | export var doesNotThrow:{ 48 | (block:Function, message?:string): void; 49 | (block:Function, error:Function, message?:string): void; 50 | (block:Function, error:RegExp, message?:string): void; 51 | (block:Function, error:(err:any) => boolean, message?:string): void; 52 | }; 53 | 54 | export function ifError(value:any):void; 55 | 56 | export interface Options { 57 | assertion?: empower.Options; 58 | output?: powerAssertFormatter.Options; 59 | } 60 | 61 | export function customize(options:Options):typeof assert; 62 | } 63 | 64 | declare module "power-assert" { 65 | export = assert; 66 | } 67 | -------------------------------------------------------------------------------- /typings/sinon/sinon.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Sinon 1.8.1 2 | // Project: http://sinonjs.org/ 3 | // Definitions by: William Sears 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | declare module Sinon { 7 | interface SinonSpyCallApi { 8 | // Properties 9 | thisValue: any; 10 | args: any[]; 11 | exception: any; 12 | returnValue: any; 13 | 14 | // Methods 15 | calledOn(obj: any): boolean; 16 | calledWith(...args: any[]): boolean; 17 | calledWithExactly(...args: any[]): boolean; 18 | calledWithMatch(...args: any[]): boolean; 19 | notCalledWith(...args: any[]): boolean; 20 | notCalledWithMatch(...args: any[]): boolean; 21 | returned(value: any): boolean; 22 | threw(): boolean; 23 | threw(type: string): boolean; 24 | threw(obj: any): boolean; 25 | callArg(pos: number): void; 26 | callArgOn(pos: number, obj: any, ...args: any[]): void; 27 | callArgWith(pos: number, ...args: any[]): void; 28 | callArgOnWith(pos: number, obj: any, ...args: any[]): void; 29 | yield(...args: any[]): void; 30 | yieldOn(obj: any, ...args: any[]): void; 31 | yieldTo(property: string, ...args: any[]): void; 32 | yieldToOn(property: string, obj: any, ...args: any[]): void; 33 | } 34 | 35 | interface SinonSpyCall extends SinonSpyCallApi { 36 | calledBefore(call: SinonSpyCall): boolean; 37 | calledAfter(call: SinonSpyCall): boolean; 38 | calledWithNew(call: SinonSpyCall): boolean; 39 | } 40 | 41 | interface SinonSpy extends SinonSpyCallApi { 42 | // Properties 43 | callCount: number; 44 | called: boolean; 45 | notCalled: boolean; 46 | calledOnce: boolean; 47 | calledTwice: boolean; 48 | calledThrice: boolean; 49 | firstCall: SinonSpyCall; 50 | secondCall: SinonSpyCall; 51 | thirdCall: SinonSpyCall; 52 | lastCall: SinonSpyCall; 53 | thisValues: any[]; 54 | args: any[][]; 55 | exceptions: any[]; 56 | returnValues: any[]; 57 | 58 | // Methods 59 | (...args: any[]): any; 60 | calledBefore(anotherSpy: SinonSpy): boolean; 61 | calledAfter(anotherSpy: SinonSpy): boolean; 62 | calledWithNew(spy: SinonSpy): boolean; 63 | withArgs(...args: any[]): SinonSpy; 64 | alwaysCalledOn(obj: any): boolean; 65 | alwaysCalledWith(...args: any[]): boolean; 66 | alwaysCalledWithExactly(...args: any[]): boolean; 67 | alwaysCalledWithMatch(...args: any[]): boolean; 68 | neverCalledWith(...args: any[]): boolean; 69 | neverCalledWithMatch(...args: any[]): boolean; 70 | alwaysThrew(): boolean; 71 | alwaysThrew(type: string): boolean; 72 | alwaysThrew(obj: any): boolean; 73 | alwaysReturned(): boolean; 74 | invokeCallback(...args: any[]): void; 75 | getCall(n: number): SinonSpyCall; 76 | reset(): void; 77 | printf(format: string, ...args: any[]): string; 78 | restore(): void; 79 | } 80 | 81 | interface SinonSpyStatic { 82 | (): SinonSpy; 83 | (func: any): SinonSpy; 84 | (obj: any, method: string): SinonSpy; 85 | } 86 | 87 | interface SinonStatic { 88 | spy: SinonSpyStatic; 89 | } 90 | 91 | interface SinonStub extends SinonSpy { 92 | resetBehavior(): void; 93 | returns(obj: any): SinonStub; 94 | returnsArg(index: number): SinonStub; 95 | throws(type?: string): SinonStub; 96 | throws(obj: any): SinonStub; 97 | callsArg(index: number): SinonStub; 98 | callsArgOn(index: number, context: any): SinonStub; 99 | callsArgWith(index: number, ...args: any[]): SinonStub; 100 | callsArgOnWith(index: number, context: any, ...args: any[]): SinonStub; 101 | callsArgAsync(index: number): SinonStub; 102 | callsArgOnAsync(index: number, context: any): SinonStub; 103 | callsArgWithAsync(index: number, ...args: any[]): SinonStub; 104 | callsArgOnWithAsync(index: number, context: any, ...args: any[]): SinonStub; 105 | onCall(n: number): SinonStub; 106 | onFirstCall(): SinonStub; 107 | onSecondCall(): SinonStub; 108 | onThirdCall(): SinonStub; 109 | yields(...args: any[]): SinonStub; 110 | yieldsOn(context: any, ...args: any[]): SinonStub; 111 | yieldsTo(property: string, ...args: any[]): SinonStub; 112 | yieldsToOn(property: string, context: any, ...args: any[]): SinonStub; 113 | yieldsAsync(...args: any[]): SinonStub; 114 | yieldsOnAsync(context: any, ...args: any[]): SinonStub; 115 | yieldsToAsync(property: string, ...args: any[]): SinonStub; 116 | yieldsToOnAsync(property: string, context: any, ...args: any[]): SinonStub; 117 | withArgs(...args: any[]): SinonStub; 118 | } 119 | 120 | interface SinonStubStatic { 121 | (): SinonStub; 122 | (obj: any): SinonStub; 123 | (obj: any, method: string): SinonStub; 124 | (obj: any, method: string, func: any): SinonStub; 125 | } 126 | 127 | interface SinonStatic { 128 | stub: SinonStubStatic; 129 | } 130 | 131 | interface SinonExpectation extends SinonStub { 132 | atLeast(n: number): SinonExpectation; 133 | atMost(n: number): SinonExpectation; 134 | never(): SinonExpectation; 135 | once(): SinonExpectation; 136 | twice(): SinonExpectation; 137 | thrice(): SinonExpectation; 138 | exactly(n: number): SinonExpectation; 139 | withArgs(...args: any[]): SinonExpectation; 140 | withExactArgs(...args: any[]): SinonExpectation; 141 | on(obj: any): SinonExpectation; 142 | verify(): SinonExpectation; 143 | restore(): void; 144 | } 145 | 146 | interface SinonExpectationStatic { 147 | create(methodName?: string): SinonExpectation; 148 | } 149 | 150 | interface SinonMock { 151 | expects(method: string): SinonExpectation; 152 | restore(): void; 153 | verify(): void; 154 | } 155 | 156 | interface SinonMockStatic { 157 | (): SinonExpectation; 158 | (obj: any): SinonMock; 159 | } 160 | 161 | interface SinonStatic { 162 | expectation: SinonExpectationStatic; 163 | mock: SinonMockStatic; 164 | } 165 | 166 | interface SinonFakeTimers { 167 | now: number; 168 | create(now: number): SinonFakeTimers; 169 | setTimeout(callback: (...args: any[]) => void, timeout: number, ...args: any[]): number; 170 | clearTimeout(id: number): void; 171 | setInterval(callback: (...args: any[]) => void, timeout: number, ...args: any[]): number; 172 | clearInterval(id: number): void; 173 | tick(ms: number): number; 174 | reset(): void; 175 | Date(): Date; 176 | Date(year: number): Date; 177 | Date(year: number, month: number): Date; 178 | Date(year: number, month: number, day: number): Date; 179 | Date(year: number, month: number, day: number, hour: number): Date; 180 | Date(year: number, month: number, day: number, hour: number, minute: number): Date; 181 | Date(year: number, month: number, day: number, hour: number, minute: number, second: number): Date; 182 | Date(year: number, month: number, day: number, hour: number, minute: number, second: number, ms: number): Date; 183 | restore(): void; 184 | } 185 | 186 | interface SinonFakeTimersStatic { 187 | (): SinonFakeTimers; 188 | (...timers: string[]): SinonFakeTimers; 189 | (now: number, ...timers: string[]): SinonFakeTimers; 190 | } 191 | 192 | interface SinonStatic { 193 | useFakeTimers: SinonFakeTimersStatic; 194 | clock: SinonFakeTimers; 195 | } 196 | 197 | interface SinonFakeUploadProgress { 198 | eventListeners: { 199 | progress: any[]; 200 | load: any[]; 201 | abort: any[]; 202 | error: any[]; 203 | }; 204 | 205 | addEventListener(event: string, listener: (e: Event) => any): void; 206 | removeEventListener(event: string, listener: (e: Event) => any): void; 207 | dispatchEvent(event: Event): void; 208 | } 209 | 210 | interface SinonFakeXMLHttpRequest { 211 | // Properties 212 | onCreate: (xhr: SinonFakeXMLHttpRequest) => void; 213 | url: string; 214 | method: string; 215 | requestHeaders: any; 216 | requestBody: string; 217 | status: number; 218 | statusText: string; 219 | async: boolean; 220 | username: string; 221 | password: string; 222 | withCredentials: boolean; 223 | upload: SinonFakeUploadProgress; 224 | responseXML: Document; 225 | getResponseHeader(header: string): string; 226 | getAllResponseHeaders(): any; 227 | 228 | // Methods 229 | restore(): void; 230 | useFilters: boolean; 231 | addFilter(filter: (method: string, url: string, async: boolean, username: string, password: string) => boolean): void; 232 | setResponseHeaders(headers: any): void; 233 | setResponseBody(body: string): void; 234 | respond(status: number, headers: any, body: string): void; 235 | autoRespond(ms: number): void; 236 | } 237 | 238 | interface SinonFakeXMLHttpRequestStatic { 239 | (): SinonFakeXMLHttpRequest; 240 | } 241 | 242 | interface SinonStatic { 243 | useFakeXMLHttpRequest: SinonFakeXMLHttpRequestStatic; 244 | FakeXMLHttpRequest: SinonFakeXMLHttpRequest; 245 | } 246 | 247 | interface SinonFakeServer { 248 | // Properties 249 | autoRespond: boolean; 250 | autoRespondAfter: number; 251 | fakeHTTPMethods: boolean; 252 | getHTTPMethod: (request: SinonFakeXMLHttpRequest) => string; 253 | requests: SinonFakeXMLHttpRequest[]; 254 | 255 | // Methods 256 | respondWith(body: string): void; 257 | respondWith(response: any[]): void; 258 | respondWith(fn: (xhr: SinonFakeXMLHttpRequest) => void): void; 259 | respondWith(url: string, body: string): void; 260 | respondWith(url: string, response: any[]): void; 261 | respondWith(url: string, fn: (xhr: SinonFakeXMLHttpRequest) => void): void; 262 | respondWith(method: string, url: string, body: string): void; 263 | respondWith(method: string, url: string, response: any[]): void; 264 | respondWith(method: string, url: string, fn: (xhr: SinonFakeXMLHttpRequest) => void): void; 265 | respondWith(url: RegExp, body: string): void; 266 | respondWith(url: RegExp, response: any[]): void; 267 | respondWith(url: RegExp, fn: (xhr: SinonFakeXMLHttpRequest) => void): void; 268 | respondWith(method: string, url: RegExp, body: string): void; 269 | respondWith(method: string, url: RegExp, response: any[]): void; 270 | respondWith(method: string, url: RegExp, fn: (xhr: SinonFakeXMLHttpRequest) => void): void; 271 | respond(): void; 272 | restore(): void; 273 | } 274 | 275 | interface SinonFakeServerStatic { 276 | create(): SinonFakeServer; 277 | } 278 | 279 | interface SinonStatic { 280 | fakeServer: SinonFakeServerStatic; 281 | fakeServerWithClock: SinonFakeServerStatic; 282 | } 283 | 284 | interface SinonExposeOptions { 285 | prefix?: string; 286 | includeFail?: boolean; 287 | } 288 | 289 | interface SinonAssert { 290 | // Properties 291 | failException: string; 292 | fail: (message?: string) => void; // Overridable 293 | pass: (assertion: any) => void; // Overridable 294 | 295 | // Methods 296 | notCalled(spy: SinonSpy): void; 297 | called(spy: SinonSpy): void; 298 | calledOnce(spy: SinonSpy): void; 299 | calledTwice(spy: SinonSpy): void; 300 | calledThrice(spy: SinonSpy): void; 301 | callCount(spy: SinonSpy, count: number): void; 302 | callOrder(...spies: SinonSpy[]): void; 303 | calledOn(spy: SinonSpy, obj: any): void; 304 | alwaysCalledOn(spy: SinonSpy, obj: any): void; 305 | calledWith(spy: SinonSpy, ...args: any[]): void; 306 | alwaysCalledWith(spy: SinonSpy, ...args: any[]): void; 307 | neverCalledWith(spy: SinonSpy, ...args: any[]): void; 308 | calledWithExactly(spy: SinonSpy, ...args: any[]): void; 309 | alwaysCalledWithExactly(spy: SinonSpy, ...args: any[]): void; 310 | calledWithMatch(spy: SinonSpy, ...args: any[]): void; 311 | alwaysCalledWithMatch(spy: SinonSpy, ...args: any[]): void; 312 | neverCalledWithMatch(spy: SinonSpy, ...args: any[]): void; 313 | threw(spy: SinonSpy): void; 314 | threw(spy: SinonSpy, exception: string): void; 315 | threw(spy: SinonSpy, exception: any): void; 316 | alwaysThrew(spy: SinonSpy): void; 317 | alwaysThrew(spy: SinonSpy, exception: string): void; 318 | alwaysThrew(spy: SinonSpy, exception: any): void; 319 | expose(obj: any, options?: SinonExposeOptions): void; 320 | } 321 | 322 | interface SinonStatic { 323 | assert: SinonAssert; 324 | } 325 | 326 | interface SinonMatcher { 327 | and(expr: SinonMatcher): SinonMatcher; 328 | or(expr: SinonMatcher): SinonMatcher; 329 | } 330 | 331 | interface SinonMatch { 332 | (value: number): SinonMatcher; 333 | (value: string): SinonMatcher; 334 | (expr: RegExp): SinonMatcher; 335 | (obj: any): SinonMatcher; 336 | (callback: (value: any) => boolean): SinonMatcher; 337 | any: SinonMatcher; 338 | defined: SinonMatcher; 339 | truthy: SinonMatcher; 340 | falsy: SinonMatcher; 341 | bool: SinonMatcher; 342 | number: SinonMatcher; 343 | string: SinonMatcher; 344 | object: SinonMatcher; 345 | func: SinonMatcher; 346 | array: SinonMatcher; 347 | regexp: SinonMatcher; 348 | date: SinonMatcher; 349 | same(obj: any): SinonMatcher; 350 | typeOf(type: string): SinonMatcher; 351 | instanceOf(type: any): SinonMatcher; 352 | has(property: string, expect?: any): SinonMatcher; 353 | hasOwn(property: string, expect?: any): SinonMatcher; 354 | } 355 | 356 | interface SinonStatic { 357 | match: SinonMatch; 358 | } 359 | 360 | interface SinonSandboxConfig { 361 | injectInto?: any; 362 | properties?: string[]; 363 | useFakeTimers?: any; 364 | useFakeServer?: any; 365 | } 366 | 367 | interface SinonSandbox { 368 | clock: SinonFakeTimers; 369 | requests: SinonFakeXMLHttpRequest; 370 | server: SinonFakeServer; 371 | spy: SinonSpyStatic; 372 | stub: SinonStubStatic; 373 | mock: SinonMockStatic; 374 | useFakeTimers: SinonFakeTimersStatic; 375 | useFakeXMLHttpRequest: SinonFakeXMLHttpRequestStatic; 376 | useFakeServer(): SinonFakeServer; 377 | restore(): void; 378 | } 379 | 380 | interface SinonSandboxStatic { 381 | create(): SinonSandbox; 382 | create(config: SinonSandboxConfig): SinonSandbox; 383 | } 384 | 385 | interface SinonStatic { 386 | sandbox: SinonSandboxStatic; 387 | } 388 | 389 | interface SinonTestConfig { 390 | injectIntoThis?: boolean; 391 | injectInto?: any; 392 | properties?: string[]; 393 | useFakeTimers?: boolean; 394 | useFakeServer?: boolean; 395 | } 396 | 397 | interface SinonTestWrapper extends SinonSandbox { 398 | (...args: any[]): any; 399 | } 400 | 401 | interface SinonStatic { 402 | config: SinonTestConfig; 403 | test(fn: (...args: any[]) => any): SinonTestWrapper; 404 | testCase(tests: any): any; 405 | } 406 | 407 | // Utility overridables 408 | interface SinonStatic { 409 | createStubInstance(constructor: any): SinonStub; 410 | format(obj: any): string; 411 | log(message: string): void; 412 | restore(object: any): void; 413 | } 414 | } 415 | 416 | declare var sinon: Sinon.SinonStatic; 417 | 418 | declare module "sinon" { 419 | export = sinon; 420 | } 421 | --------------------------------------------------------------------------------