├── .gitignore ├── README.md ├── bundler.js ├── dist ├── index.d.ts ├── index.js └── typescript-definition-tester.d.ts ├── package.json ├── src └── index.ts ├── test ├── examples │ ├── compile.ts │ ├── compileDirectory.ts │ ├── test.interface.d.ts │ └── walk.ts └── index.ts ├── tsconfig.json └── wercker.yml /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | test/examples/**/*.js 3 | testOut/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Purpose 2 | 3 | The purpose of this repository is to wrap the TypeScript compiler so that a consumer can easily test their ambient module declarations against example *.ts files. 4 | This module uses chai assertions so that a user can easily add this step to existing unit test infrastructure. 5 | 6 | [![wercker status](https://app.wercker.com/status/2ad0ff2e7585e4ff41477e6b6876acad/m "wercker status")](https://app.wercker.com/project/bykey/2ad0ff2e7585e4ff41477e6b6876acad) 7 | 8 | ## Install 9 | 10 | * Add typescript-definition-tester to your devDependencies property in your package.json file 11 | ``` 12 | npm install typescript-definition-tester --save-dev 13 | ``` 14 | * [optional] Link the typescript-definition-tester.d.ts file using tsd `tsd link --save` 15 | 16 | ## Testing 17 | 18 | The recommended way to test ambient module declarations is to create an "examples" directory in your test folder. Then, you can pull in these *.ts example files 19 | in a single test file that will pass these files to the TypeScript compiler. 20 | 21 | Example: 22 | 23 | ``` 24 | /// 25 | 26 | import * as ts from "typescript"; 27 | import * as tt from "typescript-definition-tester"; 28 | import * as fs from "fs"; 29 | import * as chai from "chai"; 30 | 31 | describe('ambient declaration tests', () => { 32 | it('should compile examples successfully against my-module.d.ts', (done) => { 33 | tt.compileDirectory( 34 | __dirname + '/examples', 35 | (fileName: string) => fileName.indexOf('.ts') > -1, 36 | () => done() 37 | ); 38 | }); 39 | }); 40 | ``` 41 | 42 | You should be able to run this test file with mocha `mocha test/my-test-file.js`. The above example is written in TypeScript. You will need to compile this using `tsc --module commonjs test/my-test-file.js` or you can just write your test using normal JavaScript. -------------------------------------------------------------------------------- /bundler.js: -------------------------------------------------------------------------------- 1 | var dts = require('dts-bundle'); 2 | var pkg = require('./package.json'); 3 | 4 | dts.bundle({ 5 | name: pkg.name, 6 | main: 'dist/index.d.ts' 7 | }); -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "typescript"; 2 | export declare type DoneFunction = (err: any, results?: string[]) => void; 3 | export declare type FilterFunction = (fileName: string) => boolean; 4 | export declare function compile(fileNames: string[], options: ts.CompilerOptions, done: Function): void; 5 | export declare function compileDirectory(path: string, done: Function): void; 6 | export declare function compileDirectory(path: string, options: ts.CompilerOptions, done: Function): void; 7 | export declare function compileDirectory(path: string, filter: FilterFunction, done: Function): void; 8 | export declare function compileDirectory(path: string, filter: FilterFunction, options: ts.CompilerOptions, done: Function): void; 9 | export declare function walk(dir: string, done: DoneFunction): void; 10 | export declare function walk(dir: string, filter: FilterFunction, done: DoneFunction): void; 11 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const ts = require("typescript"); 4 | const fs = require("fs"); 5 | const _ = require("lodash"); 6 | const AssertionError = require("assertion-error"); 7 | var defaultCompilerOptions = { 8 | noEmitOnError: true, 9 | noImplicitAny: true, 10 | target: ts.ScriptTarget.ES5, 11 | module: ts.ModuleKind.CommonJS 12 | }; 13 | function handleDiagnostics(type, diagnostics) { 14 | diagnostics.forEach(diagnostic => { 15 | var { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); 16 | var message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); 17 | throw new AssertionError(`${type}: ${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`, { 18 | actual: diagnostic 19 | }); 20 | }); 21 | } 22 | function compile(fileNames, options, done) { 23 | try { 24 | const program = ts.createProgram(fileNames, options); 25 | // TODO: this is generating errors so disabling for now. Will continue to investigate. 26 | // handleDiagnostics('Declaration', program.getDeclarationDiagnostics()); 27 | handleDiagnostics('Global', program.getGlobalDiagnostics()); 28 | console.log('Global finished'); 29 | handleDiagnostics('Semantic', program.getSemanticDiagnostics()); 30 | console.log('Semantic finished'); 31 | handleDiagnostics('Syntactic', program.getSyntacticDiagnostics()); 32 | console.log('Syntactic finished'); 33 | done(); 34 | } 35 | catch (e) { 36 | done(e); 37 | } 38 | } 39 | exports.compile = compile; 40 | function compileDirectory(path, filter, options, done) { 41 | if (!done) { 42 | if (!options) { 43 | done = filter; 44 | filter = undefined; 45 | } 46 | else { 47 | done = options; 48 | if (!_.isFunction(filter)) { 49 | options = filter; 50 | options = undefined; 51 | } 52 | } 53 | } 54 | options = _.merge(defaultCompilerOptions, (options || {})); 55 | walk(path, filter, (err, results) => { 56 | if (err) { 57 | console.log('error error error'); 58 | throw new AssertionError('Error while walking directory for files.', { 59 | actual: err 60 | }); 61 | } 62 | else { 63 | compile(results, options, done); 64 | } 65 | }); 66 | } 67 | exports.compileDirectory = compileDirectory; 68 | function walk(dir, filter, done) { 69 | if (!done) { 70 | done = filter; 71 | filter = undefined; 72 | } 73 | var results = []; 74 | fs.readdir(dir, function (err, list) { 75 | if (err) { 76 | return done(err); 77 | } 78 | var i = 0; 79 | (function next() { 80 | var file = list[i++]; 81 | if (!file) 82 | return done(null, results); 83 | file = dir + '/' + file; 84 | fs.stat(file, function (err, stat) { 85 | if (stat && stat.isDirectory()) { 86 | walk(file, function (err, res) { 87 | results = results.concat(res); 88 | next(); 89 | }); 90 | } 91 | else { 92 | if (!filter || filter(file)) { 93 | results.push(file); 94 | } 95 | next(); 96 | } 97 | }); 98 | })(); 99 | }); 100 | } 101 | exports.walk = walk; 102 | ; 103 | -------------------------------------------------------------------------------- /dist/typescript-definition-tester.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by dts-bundle v0.2.0 2 | 3 | declare module 'typescript-definition-tester' { 4 | import * as ts from "typescript"; 5 | export type DoneFunction = (err: any, results?: string[]) => void; 6 | export type FilterFunction = (fileName: string) => boolean; 7 | export function compile(fileNames: string[], options: ts.CompilerOptions, done: Function): void; 8 | export function compileDirectory(path: string, done: Function): void; 9 | export function compileDirectory(path: string, options: ts.CompilerOptions, done: Function): void; 10 | export function compileDirectory(path: string, filter: FilterFunction, done: Function): void; 11 | export function compileDirectory(path: string, filter: FilterFunction, options: ts.CompilerOptions, done: Function): void; 12 | export function walk(dir: string, done: DoneFunction): void; 13 | export function walk(dir: string, filter: FilterFunction, done: DoneFunction): void; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-definition-tester", 3 | "version": "0.0.6", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build": "tsc --module CommonJS --declaration --target ES6 ./src/index.ts --outDir dist/ && tsc --module CommonJS ./test/index.ts --outDir testOut/", 8 | "postbuild": "node bundler.js", 9 | "pretest": "npm run build", 10 | "test": "mocha testOut/test/index.js" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/adamcarr/typescript-definition-tester.git" 15 | }, 16 | "keywords": [ 17 | "typescript" 18 | ], 19 | "author": { 20 | "name": "Adam Carr", 21 | "email": "adam.carr@gmail.com", 22 | "url": "http://blog.adamcarr.net" 23 | }, 24 | "license": "MIT", 25 | "devDependencies": { 26 | "@types/assertion-error": "^1.1.0", 27 | "@types/lodash": "^4.14.108", 28 | "@types/mocha": "^5.2.0", 29 | "@types/node": "8", 30 | "bluebird": "^2.9.24", 31 | "mocha": "^5.1.1" 32 | }, 33 | "typescript": { 34 | "definition": "./dist/typescript-definition-tester.d.ts" 35 | }, 36 | "dependencies": { 37 | "assertion-error": "^1.0.1", 38 | "dts-bundle": "^0.2.0", 39 | "lodash": "^3.6.0" 40 | }, 41 | "peerDependencies": { 42 | "typescript": "1.x || 2.x" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "typescript"; 2 | import * as fs from "fs"; 3 | import * as _ from "lodash"; 4 | import AssertionError = require("assertion-error"); 5 | 6 | var defaultCompilerOptions: ts.CompilerOptions = { 7 | noEmitOnError: true, 8 | noImplicitAny: true, 9 | target: ts.ScriptTarget.ES5, 10 | module: ts.ModuleKind.CommonJS 11 | }; 12 | 13 | function handleDiagnostics(type: string, diagnostics: ReadonlyArray) { 14 | diagnostics.forEach(diagnostic => { 15 | var { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); 16 | var message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); 17 | throw new AssertionError(`${type}: ${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`, { 18 | actual: diagnostic 19 | }); 20 | }); 21 | } 22 | 23 | export type DoneFunction = (err: any, results?: string[]) => void; 24 | export type FilterFunction = (fileName: string) => boolean; 25 | 26 | export function compile(fileNames: string[], options: ts.CompilerOptions, done: Function): void { 27 | try { 28 | const program = ts.createProgram(fileNames, options); 29 | 30 | // TODO: this is generating errors so disabling for now. Will continue to investigate. 31 | // handleDiagnostics('Declaration', program.getDeclarationDiagnostics()); 32 | handleDiagnostics('Global', program.getGlobalDiagnostics()); 33 | handleDiagnostics('Semantic', program.getSemanticDiagnostics()); 34 | handleDiagnostics('Syntactic', program.getSyntacticDiagnostics()); 35 | done(); 36 | } 37 | catch (e) { 38 | done(e); 39 | } 40 | } 41 | 42 | export function compileDirectory(path: string, done: Function): void; 43 | export function compileDirectory(path: string, options: ts.CompilerOptions, done: Function): void; 44 | export function compileDirectory(path: string, filter: FilterFunction, done: Function): void; 45 | export function compileDirectory(path: string, filter: FilterFunction, options: ts.CompilerOptions, done: Function): void; 46 | export function compileDirectory(path: string, filter?: any, options?: any, done?: Function): void { 47 | if (!done) { 48 | if (!options) { 49 | done = filter; 50 | filter = undefined; 51 | } else { 52 | done = options; 53 | if (!_.isFunction(filter)) { 54 | options = filter; 55 | options = undefined; 56 | } 57 | } 58 | } 59 | 60 | options = _.merge(defaultCompilerOptions, (options || {})); 61 | 62 | walk(path, filter, (err, results) => { 63 | if (err) { 64 | console.log('error error error') 65 | throw new AssertionError('Error while walking directory for files.', { 66 | actual: err 67 | }); 68 | } else { 69 | compile(results, options, done); 70 | } 71 | }); 72 | } 73 | 74 | export function walk(dir: string, done: DoneFunction): void; 75 | export function walk(dir: string, filter: FilterFunction, done: DoneFunction): void; 76 | export function walk(dir: string, filter: FilterFunction | DoneFunction, done?: DoneFunction): void { 77 | if (!done) { 78 | done = filter; 79 | filter = undefined; 80 | } 81 | 82 | var results = []; 83 | fs.readdir(dir, function(err, list) { 84 | if (err) { 85 | return done(err); 86 | } 87 | var i = 0; 88 | (function next() { 89 | var file = list[i++]; 90 | if (!file) return done(null, results); 91 | file = dir + '/' + file; 92 | fs.stat(file, function(err, stat) { 93 | if (stat && stat.isDirectory()) { 94 | walk(file, function(err, res) { 95 | results = results.concat(res); 96 | next(); 97 | }); 98 | } else { 99 | if (!filter || (filter as FilterFunction)(file)) { 100 | results.push(file); 101 | } 102 | next(); 103 | } 104 | }); 105 | })(); 106 | }); 107 | }; 108 | -------------------------------------------------------------------------------- /test/examples/compile.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as tt from "typescript-definition-tester"; 3 | import * as test from 'test'; 4 | 5 | tt.compile(['somefilename'], {}, () => {}); 6 | 7 | const person: test.IPerson = { 8 | name: 'Adam' 9 | } -------------------------------------------------------------------------------- /test/examples/compileDirectory.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as tt from "typescript-definition-tester"; 3 | 4 | tt.compileDirectory('somePath', () => { }); 5 | tt.compileDirectory('somePath', {}, () => { }); 6 | tt.compileDirectory('somePath', (fileName) => true, () => { }); 7 | tt.compileDirectory('somePath', (fileName) => true, {}, () => { }); -------------------------------------------------------------------------------- /test/examples/test.interface.d.ts: -------------------------------------------------------------------------------- 1 | declare module "test" { 2 | export interface IPerson { 3 | name: string; 4 | } 5 | } -------------------------------------------------------------------------------- /test/examples/walk.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as tt from "typescript-definition-tester"; 3 | 4 | tt.walk('dirname', (err, result) => { }); 5 | tt.walk('dirname', (fileName) => true, (err, result) => { }); -------------------------------------------------------------------------------- /test/index.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "typescript"; 2 | import * as tt from "../src/index"; 3 | import * as fs from "fs"; 4 | 5 | describe('ambient declaration tests', function () { 6 | this.timeout(5000); 7 | it('should compile examples successfully against typescript-definition-tester.d.ts', (done) => { 8 | tt.compileDirectory( 9 | './test/examples', 10 | (fileName: string) => { 11 | console.log('fileName', fileName); 12 | return fileName.indexOf('.ts') > -1; 13 | }, 14 | () => done() 15 | ); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "es6" 5 | ], 6 | "module": "commonjs", 7 | "sourceMap": true, 8 | "target": "es6", 9 | "types": [ 10 | "assertion-error", 11 | "lodash", 12 | "node", 13 | "mocha" 14 | ], 15 | "typeRoots": [ 16 | "node_modules/@types" 17 | ] 18 | }, 19 | "compileOnSave": false 20 | } -------------------------------------------------------------------------------- /wercker.yml: -------------------------------------------------------------------------------- 1 | box: node 2 | # Build definition 3 | # Build definition 4 | build: 5 | # The steps that will be executed on build 6 | steps: 7 | # A step that executes `npm install` command 8 | - npm-install 9 | # A step that executes `npm test` command 10 | - script: 11 | name: dev-setup 12 | code: | 13 | sudo npm install -g mocha && sudo npm install typescript 14 | - npm-test 15 | 16 | # A custom script step, name value is used in the UI 17 | # and the code value contains the command that get executed 18 | - script: 19 | name: echo nodejs information 20 | code: | 21 | echo "node version $(node -v) running" 22 | echo "npm version $(npm -v) running" --------------------------------------------------------------------------------