Comparing version 1.6.4 to 1.7.0
{ | ||
"author": "basarat", | ||
"name": "grunt-ts", | ||
"description": "Compile and manage your TypeScript project", | ||
"version": "1.6.4", | ||
"homepage": "https://github.com/basarat/grunt-ts", | ||
"description": "Compile and manage your TypeScript project", | ||
"version": "1.7.0", | ||
"homepage": "https://github.com/grunt-ts/grunt-ts", | ||
"repository": { | ||
"type": "git", | ||
"url": "git@github.com:basarat/grunt-ts.git" | ||
"url": "git@github.com:grunt-ts/grunt-ts.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/basarat/grunt-ts/issues" | ||
"url": "https://github.com/grunt-ts/grunt-ts/issues" | ||
}, | ||
@@ -17,3 +17,3 @@ "licenses": [ | ||
"type": "MIT", | ||
"url": "https://github.com/basarat/grunt-ts/blob/master/LICENSE" | ||
"url": "https://github.com/grunt-ts/grunt-ts/blob/master/LICENSE" | ||
} | ||
@@ -30,13 +30,20 @@ ], | ||
"email": "viralidealogue@gmail.com" | ||
}, | ||
{ | ||
"name": "bartvds", | ||
"email": "bartvanderschoor@gmail.com" | ||
} | ||
], | ||
], | ||
"engines": { | ||
"node": ">= 0.8.0" | ||
}, | ||
"scripts": { | ||
"test": "grunt test" | ||
}, | ||
"dependencies": { | ||
"typescript": "0.9.5", | ||
"chokidar": "0.6.2", | ||
"shelljs": "0.1.4", | ||
"chokidar": "0.6.2", | ||
"underscore": "1.5.1", | ||
"underscore.string": "2.3.3" | ||
"underscore.string": "2.3.3", | ||
"es6-promise": "~0.1.1" | ||
}, | ||
@@ -48,5 +55,9 @@ "peerDependencies": { | ||
"grunt": "~0.4.0", | ||
"grunt-tslint": "~0.4.0", | ||
"grunt-contrib-clean": "~0.4.0", | ||
"grunt-contrib-watch": "~0.5.1", | ||
"grunt-contrib-nodeunit": "~0.1.2" | ||
"grunt-contrib-jshint": "~0.8.0", | ||
"grunt-contrib-nodeunit": "~0.2.2", | ||
"tslint-path-formatter": "~0.1.1", | ||
"source-map-support": "~0.2.5", | ||
"jshint-path-reporter": "~0.1.3" | ||
}, | ||
@@ -56,4 +67,5 @@ "optionalDependencies": {}, | ||
"gruntplugin", | ||
"typescript" | ||
"typescript", | ||
"compiler" | ||
] | ||
} |
289
README.md
@@ -1,22 +0,23 @@ | ||
grunt-ts | ||
================ | ||
Written from scratch TypeScript compiler task for GruntJS. | ||
It differs from grunt-typescript which is another excellent [grunt plugin for typescript](https://npmjs.org/package/grunt-typescript). | ||
# grunt-ts | ||
Following are the reasons why it was created. | ||
[![Build Status](https://secure.travis-ci.org/basarat/grunt-ts.png?branch=master)](http://travis-ci.org/basarat/grunt-ts) [![NPM version](https://badge.fury.io/js/grunt-ts.png)](http://badge.fury.io/js/grunt-ts) | ||
- This is written in [TypeScript](https://github.com/basarat/grunt-ts/blob/master/tasks/ts.ts) | ||
- Gives a typescript development workflow in addition to simple file compilation. | ||
- Super simple to update to the [latest version of the typescript](https://github.com/basarat/grunt-ts/commit/ffede564f2b20bc4dc207cb1a30dc57db7c44fe5) | ||
Written from scratch TypeScript compiler task for GruntJS. It differs from grunt-typescript which is another excellent [grunt plugin for TypeScript](https://npmjs.org/package/grunt-typescript). | ||
Check how it can help streamline your front end development : [Sample usage with AngularJS](http://www.youtube.com/watch?v=0-6vT7xgE4Y&hd=1) | ||
Following are the reasons why grunt-ts was created: | ||
Additional / longer / more basic video tutorial : http://youtu.be/Km0DpfX5ZxM | ||
- Written in [TypeScript](https://github.com/basarat/grunt-ts/blob/master/tasks/ts.ts) | ||
- Enables a TypeScript development workflow in addition to simple file compilation. | ||
- Super simple to update to the [latest version of the TypeScript](https://github.com/basarat/grunt-ts/commit/ffede564f2b20bc4dc207cb1a30dc57db7c44fe5) | ||
*If you know Grunt. Here is a quickstart full featured [Gruntfile](https://github.com/basarat/grunt-ts/blob/master/sample/Gruntfile.js)* | ||
Check how grunt-ts can help streamline front end development: [Sample usage with AngularJS](http://www.youtube.com/watch?v=0-6vT7xgE4Y&hd=1) | ||
Following are some key features: | ||
====================== | ||
Additional / longer / more basic video tutorial: http://youtu.be/Km0DpfX5ZxM | ||
###Compiler support | ||
For a quickstart see the full featured [Gruntfile](https://github.com/basarat/grunt-ts/blob/master/sample/Gruntfile.js). | ||
## Following are some key features: | ||
### Compiler support | ||
Supports the following compiler flags in both original format and camelCase (preferred): | ||
@@ -36,24 +37,21 @@ | ||
Can also do js *file concatenation* using `--out`. Additionally supports an output directory for the generated | ||
javascript using `--outDir` flag. | ||
For file ordering look at Javascript Generation below. | ||
There is also support for js *file concatenation* using `--out`. Additionally supported is an output directory for the generated JavaScript using `--outDir` flag. For file ordering look at JavaScript Generation below. | ||
###Reference file generation | ||
Can generate a reference.ts file for you which contains a reference to all your ts files. | ||
This means you never need to cross reference files manually. Just reference `reference.ts` :) | ||
### Reference file generation | ||
Grunt-ts can generate a reference.ts file which contains a reference to all ts files. | ||
####Javascript generation and ordering | ||
Also if you specify both an out js file via `out` && a reference file via `reference` | ||
it uses the generated reference file to *order the code in the generated javascript*. | ||
This means there will never be a need to cross reference files manually, instead just reference `reference.ts` :) | ||
In your `reference.ts` file you can specify the order for the few files you care about | ||
and leave the rest to be maintained by grunt-ts. | ||
E.g. in the following case the generated javascript for `someBaseClass.ts` is guaranteed to be at the top, | ||
and the generated javascript for `main.ts`is guaranteed to be at the bottom of the single merged js file. | ||
Everything between `grunt-start` and `grunt-end` is generated and maintained | ||
for you. If there is no `grunt-start` section found, it is created for you. If `reference.ts` does not | ||
exist originally, it is created for you. | ||
#### JavaScript generation and ordering | ||
When a output file is specified via `out` in combination with a reference file via `reference` then grunt-ts uses the generated reference file to *order the code in the generated JavaScript*. | ||
Use `reference.ts` to specify the order for the few files the build really cares about and leave the rest to be maintained by grunt-ts. | ||
E.g. in the following case the generated JavaScript for `someBaseClass.ts` is guaranteed to be at the top, and the generated JavaScript for `main.ts` is guaranteed to be at the bottom of the single merged js file. | ||
Everything between `grunt-start` and `grunt-end` is generated and maintained by grunt-ts. If there is no `grunt-start` section found, it is created. If `reference.ts` does not exist originally, it is also created. | ||
```typescript | ||
@@ -63,3 +61,3 @@ | ||
// You can even put comments here and they are preserved | ||
// Put comments here and they are preserved | ||
@@ -75,9 +73,12 @@ //grunt-start | ||
####Javscript generation Redirect | ||
If you specify `outDir` all output javascript are redirected to this folder. | ||
This helps keep your source folder clean. | ||
#### JavaScript generation redirect | ||
####AMD / RequireJS support | ||
If you specify both `outDir` and `amdloader` option a Javascript requireJS loader file is created using the information | ||
available from `reference.ts`. The file consists of three sections. | ||
If an `outDir` is specified all output JavaScript is redirected to this folder to keep the source folder clean. | ||
#### AMD / RequireJS support | ||
When both `outDir` and `amdloader` options are specified a JavaScript requireJS loader file is created using the information available from `reference.ts`. | ||
The file consists of three sections.: | ||
* The initial ordered section. | ||
@@ -87,3 +88,3 @@ * A middle order independent section loaded asynchronously. | ||
e.g the following `reference` file | ||
E.g the following `reference` file: | ||
@@ -102,3 +103,3 @@ ```typescript | ||
Corresponds to an `amdloader` (edited for readability): | ||
This corresponds to an `amdloader` (edited for readability): | ||
@@ -124,58 +125,66 @@ ```typescript | ||
#####Advantage of using amdloader option | ||
The following combination of circumstances are why you would use it instead of Compiler supported AMD. | ||
##### Advantage of using amdloader option | ||
* You want to use RequireJS since you prefer to debug "js" files instead of "ts" files. | ||
This is useful in some cases and the most common way is using AMD | ||
* You want the ability to individually compile only changed files (for a faster dev-compile-run cycle) | ||
* However, File order doesn't matter to you, even when you have inter file depenendency (e.g. AngularJS runtime Dependency injection) | ||
The following combination of circumstances are the main use-case for amdloader compared to the original Compiler supported AMD: | ||
In such a case you can either create a `loader.js` manually or have grunt create it for you. | ||
* Use RequireJS since allows to debug "js" files instead of "ts" files. This is useful in some cases, the most common way is using AMD. | ||
* Keep the ability to individually compile only changed files (for a faster dev-compile-run cycle) | ||
* However, File order doesn't matter, even when there is a inter file depenendency (e.g. AngularJS runtime Dependency injection) | ||
**Further Explanation** If you use `export class Foo{}` at the root level of your file the only | ||
way to use the type information | ||
of Foo in another file is via an import statement `import foo = require('./potentially/long/path/to/Foo');` | ||
The ordering implied by this isn't necessary when using a runtime Dependency injection framework like AngularJS. | ||
Having a loader gives you the js debugging (+ async) advantages | ||
of RequireJS without the overhead of constantly requesting via `import` to get the TypeScript type inference and | ||
worrying about file paths when they are not relevant. | ||
In such a case it is possible to either create a `loader.js` manually or have grunt create one. | ||
PS: your individual file SourceMaps will continue to work. So now you can debug individual "JS" or "TS" files :) | ||
**Further Explanation** When using `export class Foo{}` at the root level of the file the only way to use the type information of Foo in another file is via an import statement: `import foo = require('./potentially/long/path/to/Foo');`. | ||
The ordering implied by this isn't necessary when using a runtime Dependency Injection framework like AngularJS. | ||
###Html 2 TypeScript support | ||
Can re-encode html files into typescript and makes them available as a variable. e.g. | ||
a file called `test.html` containing | ||
Having a loader gives the js debugging (+ async) advantages of RequireJS without the overhead of constantly requesting via `import` to get the TypeScript type inference and worrying about file paths when they are not relevant. | ||
Note: the individual file source-map will continue to work so it is possible to debug individual "JS" or "TS" files :) | ||
### Html 2 TypeScript support | ||
Grunt-ts can re-encode html files into TypeScript and make them available as a variable. | ||
For example a file called `test.html`: | ||
```html | ||
<div> Some Content </div> | ||
``` | ||
is compiled to a typescript file `test.html.ts` containing: | ||
Will be compiled to a TypeScript file `test.html.ts` containing: | ||
```typescript | ||
module test { export var html = '<div> Some content </div>' } | ||
``` | ||
so that you can use use the variable `test.html` within your typescript to get the content of test.html | ||
as a string. The motivation is to remove http requests to load templates in various front end frameworks. | ||
####Html 2 TypeScript usage in AngularJS | ||
This is great for putting variables in templateCache : http://docs.angularjs.org/api/ng.$templateCache | ||
or even using the html string directly by setting it to the `template` properties (directives/views) instead of `templateUrl` | ||
This will export the variable `test.html` within the TypeScript scope to get the content of test.html as a string, with the main benefit of limiting the http-requests needed to load templates in various front-end frameworks. | ||
####Html 2 TypeScript usage in EmberJS | ||
You can specify this string to the template on a view : http://emberjs.com/api/classes/Ember.View.html | ||
#### Html 2 TypeScript usage in AngularJS | ||
This is great for putting variables in templateCache: http://docs.angularjs.org/api/ng.$templateCache or even using the html string directly by setting it to the `template` properties (directives/views) instead of `templateUrl` | ||
#### Html 2 TypeScript usage in EmberJS | ||
It is possible to specify this string to the template on a view: http://emberjs.com/api/classes/Ember.View.html | ||
Specifically: http://stackoverflow.com/a/9867375/390330 | ||
###Live file watching and building | ||
Can watch a directory for you and recompile your typescript files when any typescript file changes, gets added, gets removed. | ||
This makes sure your project is always build ready :) | ||
### Live file watching and building | ||
Grunt-ts can watch a directory and recompile TypeScript files when any TypeScript file changes, gets added, gets removed. Internallythe `chokidar` module is used to makes sure the project is always build ready :) | ||
npm install | ||
====================== | ||
## Installation | ||
The npm package is available here : https://npmjs.org/package/grunt-ts | ||
Grunt-ts is published as [npm package](https://npmjs.org/package/grunt-ts): | ||
## Installation Documentation | ||
Install nodejs. Then install grunt-cli using `npm install -g grunt-cli`. Next you can install `grunt` and `grunt-ts` by creating a `package.json` | ||
file containing the following: | ||
````bash | ||
$ npm install grunt-ts --save-dev | ||
```` | ||
For new projects and user new to node, make sure to have installed nodejs, then install grunt-cli: | ||
````bash | ||
$ npm install -g grunt-cli | ||
```` | ||
Next install `grunt` and `grunt-ts` by creating a `package.json` file containing the following: | ||
```javascript | ||
@@ -189,75 +198,105 @@ { | ||
``` | ||
and run `npm install` from the same directory. This will download both grunt and grunt-ts for you. | ||
Then run `npm install` from the same directory. This will download both grunt and grunt-ts. | ||
## Configuration Documentation | ||
Create a `Gruntfile.js`. Modify it to load grunt-ts by adding the following lines: | ||
module.exports = function (grunt) { | ||
```javascript | ||
module.exports = function (grunt) { | ||
// load the task | ||
grunt.loadNpmTasks("grunt-ts"); | ||
// load the task | ||
grunt.loadNpmTasks("grunt-ts"); | ||
// Configure grunt here | ||
} | ||
// Configure grunt here | ||
} | ||
``` | ||
Then add some configuration for the plugin like so: | ||
Add some configuration for the plugin: | ||
grunt.initConfig({ | ||
... | ||
ts: { | ||
dev: { // a particular target | ||
src: ["test/work/**/*.ts"], // The source typescript files, http://gruntjs.com/configuring-tasks#files | ||
html: ["test/work/**/*.tpl.html"], // The source html files, https://github.com/basarat/grunt-ts#html-2-typescript-support | ||
reference: "./test/reference.ts", // If specified, generate this file that you can use for your reference management | ||
out: 'test/out.js', // If specified, generate an out.js file which is the merged js file | ||
outDir: 'test/outputdirectory', // If specified, the generate javascript files are placed here. Only works if out is not specified | ||
watch: 'test', // If specified, watches this directory for changes, and re-runs the current target | ||
options: { // use to override the default options, http://gruntjs.com/configuring-tasks#options | ||
target: 'es3', // 'es3' (default) | 'es5' | ||
module: 'commonjs', // 'amd' (default) | 'commonjs' | ||
sourceMap: true, // true (default) | false | ||
declaration: false, // true | false (default) | ||
removeComments: true // true (default) | false | ||
}, | ||
```javascript | ||
grunt.initConfig({ | ||
... | ||
ts: { | ||
// A specific target | ||
build: { | ||
// The source TypeScript files, http://gruntjs.com/configuring-tasks#files | ||
src: ["test/work/**/*.ts"], | ||
// The source html files, https://github.com/basarat/grunt-ts#html-2-typescript-support | ||
html: ["test/work/**/*.tpl.html"], | ||
// If specified, generate this file that to can use for reference management | ||
reference: "./test/reference.ts", | ||
// If specified, generate an out.js file which is the merged js file | ||
out: 'test/out.js', | ||
// If specified, the generate JavaScript files are placed here. Only works if out is not specified | ||
outDir: 'test/outputdirectory', | ||
// If specified, watches this directory for changes, and re-runs the current target | ||
watch: 'test', | ||
// Use to override the default options, http://gruntjs.com/configuring-tasks#options | ||
options: { | ||
// 'es3' (default) | 'es5' | ||
target: 'es3', | ||
// 'amd' (default) | 'commonjs' | ||
module: 'commonjs', | ||
// true (default) | false | ||
sourceMap: true, | ||
// true | false (default) | ||
declaration: false, | ||
// true (default) | false | ||
removeComments: true | ||
}, | ||
build: { // another target | ||
src: ["test/work/**/*.ts"], | ||
options: { // override the main options for this target | ||
sourceMap: false, | ||
} | ||
}, | ||
}, | ||
... | ||
}); | ||
// Another target | ||
dist: { | ||
src: ["test/work/**/*.ts"], | ||
// Override the main options for this target | ||
options: { | ||
sourceMap: false, | ||
} | ||
}, | ||
}, | ||
... | ||
}); | ||
``` | ||
I also recommend adding a default target you want to run in case you do not want to specify any arguments to grunt: | ||
It is recommended to add a default target to run in case no arguments to grunt are specified: | ||
```js | ||
grunt.registerTask("default", ["ts:build"]); | ||
``` | ||
grunt.registerTask("default", ["ts:dev"]); | ||
``` | ||
You can see/grab an up-to-date sample grunt file here: https://github.com/basarat/grunt-ts/blob/master/sample/Gruntfile.js | ||
For an example of an up-to-date configuration look at the [sample gruntfile](https://github.com/basarat/grunt-ts/blob/master/sample/Gruntfile.js) | ||
### Different configurations per target | ||
Configuration options are per target. You can see how you can have one set of default options and then override | ||
these selectively for a target (e.g `build` , `dev`, `staging` etc). | ||
This is provided by grunt : http://gruntjs.com/configuring-tasks#options | ||
### Different configurations per target | ||
Grunt-ts supports the Grunt convention of having [multiple configuration targets](http://gruntjs.com/configuring-tasks#options) per task. It is convenient to have one set of default options and then override these selectively for a target (e.g `build` , `dev`, `staging` etc). | ||
### Awesome file globs | ||
You can do pretty fancy stuff with your src file selection. | ||
Again provided by grunt : http://gruntjs.com/configuring-tasks#files | ||
# Contributing | ||
For advanced use-cases there is support for [Grunt's selection options](http://gruntjs.com/configuring-tasks#files), such as using globbing or using a callback to filter paths. | ||
## Building the project: | ||
## Contributing | ||
tsc "./tasks/ts.ts" --sourcemap --module commonjs | ||
With npm and grunt-cli installed, run the following from the root of the repository: | ||
## Running the tests: | ||
```bash | ||
$ npm install | ||
``` | ||
With npm and grunt-cli installed, run the following from the root of the repository, | ||
### Building the project: | ||
grunt ts | ||
```bash | ||
$ grunt build | ||
``` | ||
### Running the tests builds: | ||
Some tests expect failures and will be labelled. | ||
```bash | ||
$ grunt test | ||
``` | ||
We welcome new methods for writing automated tests that are a little less of a manual process. | ||
## License | ||
Licensed under the MIT License. |
367
tasks/ts.js
@@ -1,6 +0,16 @@ | ||
/// <reference path="../defs/node/node.d.ts"/> | ||
/// <reference path="../defs/grunt/gruntjs.d.ts"/> | ||
/// <reference path="../defs/underscore/underscore.d.ts"/> | ||
/// <reference path="../defs/underscore.string/underscore.string.d.ts"/> | ||
/// <reference path="../defs/tsd.d.ts"/> | ||
/* | ||
* grunt-ts | ||
* Licensed under the MIT license. | ||
*/ | ||
// Typescript imports | ||
var _ = require('underscore'); | ||
var _str = require('underscore.string'); | ||
var path = require('path'); | ||
var fs = require('fs'); | ||
// plain vanilla imports | ||
var pathSeperator = path.sep; | ||
var Promise = require('es6-promise').Promise; | ||
var ReferenceOrder; | ||
@@ -49,58 +59,133 @@ (function (ReferenceOrder) { | ||
// Typescript imports | ||
var _ = require('underscore'); | ||
var _str = require('underscore.string'); | ||
var path = require('path'); | ||
var fs = require('fs'); | ||
/** | ||
* Get a random hex value | ||
* | ||
* @returns {string} hex string | ||
*/ | ||
function getRandomHex(length) { | ||
if (typeof length === "undefined") { length = 16; } | ||
var name = ''; | ||
do { | ||
name += Math.round(Math.random() * Math.pow(16, 8)).toString(16); | ||
} while(name.length < length); | ||
// plain vanilla imports | ||
var shell = require('shelljs'); | ||
var pathSeperator = path.sep; | ||
return name.substr(0, length); | ||
} | ||
/** | ||
* Get a unique temp file | ||
* | ||
* @returns {string} unique-ish path to file in given directory. | ||
* @throws when it cannot create a temp file in the specified directory | ||
*/ | ||
function getTempFile(prefix, dir) { | ||
if (typeof dir === "undefined") { dir = ''; } | ||
prefix = (prefix ? prefix + '-' : ''); | ||
var attempts = 100; | ||
do { | ||
var name = prefix + getRandomHex(8) + '.tmp.txt'; | ||
var dest = path.join(dir, name); | ||
if (!fs.existsSync(dest)) { | ||
return dest; | ||
} | ||
attempts--; | ||
} while(attempts > 0); | ||
throw 'Cannot create temp file in ' + dir; | ||
} | ||
/** | ||
* Run a map operation async in series (simplified) | ||
*/ | ||
function asyncSeries(arr, iter) { | ||
arr = arr.slice(0); | ||
var memo = []; | ||
// Run one at a time | ||
return new Promise(function (resolve, reject) { | ||
var next = function () { | ||
if (arr.length === 0) { | ||
resolve(memo); | ||
return; | ||
} | ||
Promise.cast(iter(arr.shift())).then(function (res) { | ||
memo.push(res); | ||
next(); | ||
}, reject); | ||
}; | ||
next(); | ||
}); | ||
} | ||
function pluginFn(grunt) { | ||
// Helper | ||
function executeNode(args) { | ||
return new Promise(function (resolve, reject) { | ||
grunt.util.spawn({ | ||
cmd: 'node', | ||
args: args | ||
}, function (error, result, code) { | ||
var ret = { | ||
code: code, | ||
output: String(result) | ||
}; | ||
resolve(ret); | ||
}); | ||
}); | ||
} | ||
///////////////////////////////////////////////////////////////////// | ||
// tsc handling. | ||
//////////////////////////////////////////////////////////////////// | ||
function resolveTypeScriptBinPath(currentPath, depth) { | ||
var targetPath = path.resolve(__dirname, (new Array(depth + 1)).join("../../"), "../node_modules/typescript/bin"); | ||
if (path.resolve(currentPath, "node_modules/typescript/bin").length > targetPath.length) { | ||
return null; | ||
function resolveTypeScriptBinPath() { | ||
var ownRoot = path.resolve(path.dirname((module).filename), '..'); | ||
var userRoot = path.resolve(ownRoot, '..', '..'); | ||
var binSub = path.join('node_modules', 'typescript', 'bin'); | ||
if (fs.existsSync(path.join(userRoot, binSub))) { | ||
// Using project override | ||
return path.join(userRoot, binSub); | ||
} | ||
if (fs.existsSync(path.resolve(targetPath, "typescript.js"))) { | ||
return targetPath; | ||
} | ||
return path.join(ownRoot, binSub); | ||
} | ||
return resolveTypeScriptBinPath(currentPath, ++depth); | ||
} | ||
function getTsc(binPath) { | ||
return '"' + binPath + '/' + 'tsc"'; | ||
var pkg = JSON.parse(fs.readFileSync(path.resolve(binPath, '..', 'package.json')).toString()); | ||
grunt.log.writeln('Using tsc v' + pkg.version); | ||
return path.join(binPath, 'tsc'); | ||
} | ||
var eol = grunt.util.linefeed; | ||
var exec = shell.exec; | ||
var cwd = path.resolve("."); | ||
var tsc = getTsc(resolveTypeScriptBinPath(cwd, 0)); | ||
// Blindly runs the tsc task using provided options | ||
function compileAllFiles(files, target, task) { | ||
var cmd = files.join(' '); | ||
var args = files.slice(0); | ||
// boolean options | ||
if (task.sourceMap) | ||
cmd = cmd + ' --sourcemap'; | ||
if (task.declaration) | ||
cmd = cmd + ' --declaration'; | ||
if (task.removeComments) | ||
cmd = cmd + ' --removeComments'; | ||
if (task.noImplicitAny) | ||
cmd = cmd + ' --noImplicitAny'; | ||
if (task.noResolve) | ||
cmd = cmd + ' --noResolve'; | ||
if (task.sourceMap) { | ||
args.push('--sourcemap'); | ||
} | ||
if (task.declaration) { | ||
args.push('--declaration'); | ||
} | ||
if (task.removeComments) { | ||
args.push('--removeComments'); | ||
} | ||
if (task.noImplicitAny) { | ||
args.push('--noImplicitAny'); | ||
} | ||
if (task.noResolve) { | ||
args.push('--noResolve'); | ||
} | ||
// string options | ||
cmd = cmd + ' --target ' + task.target.toUpperCase(); | ||
cmd = cmd + ' --module ' + task.module.toLowerCase(); | ||
args.push('--target', task.target.toUpperCase()); | ||
args.push('--module', task.module.toLowerCase()); | ||
// Target options: | ||
if (target.out) { | ||
cmd = cmd + ' --out ' + target.out; | ||
args.push('--out', target.out); | ||
} | ||
@@ -111,16 +196,19 @@ if (target.outDir) { | ||
} | ||
cmd = cmd + ' --outDir ' + target.outDir; | ||
args.push('--outDir', target.outDir); | ||
} | ||
if (task.sourceRoot) { | ||
cmd = cmd + ' --sourceRoot ' + task.sourceRoot; | ||
args.push('--sourceRoot', task.sourceRoot); | ||
} | ||
if (task.mapRoot) { | ||
cmd = cmd + ' --mapRoot ' + task.mapRoot; | ||
args.push('--mapRoot', task.mapRoot); | ||
} | ||
// Locate a compiler | ||
var tsc = getTsc(resolveTypeScriptBinPath()); | ||
// To debug the tsc command | ||
if (task.verbose) { | ||
console.log(cmd.yellow); | ||
console.log(args.join(' ').yellow); | ||
} else { | ||
grunt.log.verbose.writeln(cmd.yellow); | ||
grunt.log.verbose.writeln(args.join(' ').yellow); | ||
} | ||
@@ -130,7 +218,20 @@ | ||
// Reason: passing all the files on the command line causes TSC to go in an infinite loop. | ||
var tempfilename = 'tscommand.tmp.txt'; | ||
var tscExecCommand = 'node ' + tsc + ' @' + tempfilename; | ||
fs.writeFileSync(tempfilename, cmd); | ||
var tempfilename = getTempFile('tscommand'); | ||
if (!tempfilename) { | ||
throw (new Error('cannot create temp file')); | ||
} | ||
return exec(tscExecCommand); | ||
fs.writeFileSync(tempfilename, args.join(' ')); | ||
// Execute command | ||
return executeNode([tsc, '@' + tempfilename]).then(function (result) { | ||
fs.unlinkSync(tempfilename); | ||
grunt.log.writeln(result.output); | ||
return Promise.cast(result); | ||
}, function (err) { | ||
fs.unlinkSync(tempfilename); | ||
throw err; | ||
}); | ||
} | ||
@@ -161,2 +262,3 @@ | ||
var signatureSectionPosition = 0; | ||
var i; | ||
@@ -172,3 +274,3 @@ // Read the original file if it exists | ||
for (var i = 0; i < lines.length; i++) { | ||
for (i = 0; i < lines.length; i++) { | ||
var line = _str.trim(lines[i]); | ||
@@ -178,3 +280,3 @@ | ||
if (_str.include(line, ourSignatureStart)) { | ||
//Wait for the end signature: | ||
// Wait for the end signature: | ||
signatureSectionPosition = i; | ||
@@ -188,4 +290,5 @@ inSignatureSection = true; | ||
} | ||
if (inSignatureSection) | ||
if (inSignatureSection) { | ||
continue; | ||
} | ||
@@ -232,6 +335,6 @@ // store the line | ||
// Return whether the file was changed | ||
if (lines.length == updatedFileLines.length) { | ||
if (lines.length === updatedFileLines.length) { | ||
var updated = false; | ||
for (var i = 0; i < lines.length; i++) { | ||
if (lines[i] != updatedFileLines[i]) { | ||
for (i = 0; i < lines.length; i++) { | ||
if (lines[i] !== updatedFileLines[i]) { | ||
updated = true; | ||
@@ -260,2 +363,3 @@ } | ||
var sortedGeneratedFiles = _.sortBy(generatedFiles); | ||
function isGeneratedFile(filename) { | ||
@@ -270,4 +374,4 @@ return _.indexOf(sortedGeneratedFiles, filename, true) !== -1; | ||
var referenceIntro = '/// <reference path="'; | ||
var referenceEnd = '" />'; | ||
// var referenceEnd = '" />'; | ||
// The section of unordered files | ||
@@ -286,3 +390,3 @@ var ourSignatureStart = '//grunt-start'; | ||
if (_str.include(line, ourSignatureStart)) { | ||
//Wait for the end signature: | ||
// Wait for the end signature: | ||
loopState = 1 /* unordered */; | ||
@@ -337,8 +441,10 @@ } | ||
function sharedStart(array) { | ||
if (array.length == 0) | ||
throw "Cannot find common root of empty array."; | ||
if (array.length === 0) { | ||
throw 'Cannot find common root of empty array.'; | ||
} | ||
var A = array.slice(0).sort(), firstWord = A[0], lastWord = A[A.length - 1]; | ||
if (firstWord === lastWord) | ||
if (firstWord === lastWord) { | ||
return firstWord; | ||
else { | ||
} else { | ||
var i = -1; | ||
@@ -349,3 +455,4 @@ do { | ||
var lastWordChar = lastWord.charAt(i); | ||
} while(firstWordChar == lastWordChar); | ||
} while(firstWordChar === lastWordChar); | ||
return firstWord.substring(0, i); | ||
@@ -377,3 +484,3 @@ } | ||
} else { | ||
grunt.warn("No files in reference file: " + referenceFile); | ||
grunt.warn('No files in reference file: ' + referenceFile); | ||
} | ||
@@ -432,3 +539,3 @@ if (files.before.length > 0) { | ||
//remove ts extension '.ts': | ||
// remove ts extension '.ts': | ||
file = file.substr(0, file.length - 3); | ||
@@ -440,3 +547,3 @@ | ||
// Prepend "./" to prevent "basePath" requirejs setting from interferring: | ||
file = "./" + file; | ||
file = './' + file; | ||
@@ -447,3 +554,4 @@ return file; | ||
} | ||
grunt.log.verbose.writeln("Making files relative to outDir..."); | ||
grunt.log.verbose.writeln('Making files relative to outDir...'); | ||
files.before = makeRelativeToOutDir(files.before); | ||
@@ -516,3 +624,3 @@ files.generated = makeRelativeToOutDir(files.generated); | ||
//////////////////////////////////////////////////////////////////// | ||
//html -> js processing functions: | ||
// html -> js processing functions: | ||
// Originally from karma-html2js-preprocessor | ||
@@ -523,3 +631,3 @@ // Refactored nicely in html2js grunt task | ||
var escapeContent = function (content, quoteChar) { | ||
if (typeof quoteChar === "undefined") { quoteChar = "'"; } | ||
if (typeof quoteChar === "undefined") { quoteChar = '\''; } | ||
var quoteRegexp = new RegExp('\\' + quoteChar, 'g'); | ||
@@ -532,6 +640,6 @@ var nlReplace = ''; | ||
function stripBOM(str) { | ||
return 0xFEFF == str.charCodeAt(0) ? str.substring(1) : str; | ||
return 0xFEFF === str.charCodeAt(0) ? str.substring(1) : str; | ||
} | ||
var htmlTemplate = _.template("module <%= modulename %> { export var <%= varname %> = '<%= content %>' } "); | ||
var htmlTemplate = _.template('module <%= modulename %> { export var <%= varname %> = \'<%= content %>\' } '); | ||
@@ -550,3 +658,3 @@ // Compile an HTML file to a TS file | ||
// Write the content to a file | ||
var outputfile = filename + ".ts"; | ||
var outputfile = filename + '.ts'; | ||
@@ -562,4 +670,5 @@ fs.writeFileSync(outputfile, fileContent); | ||
function generateTemplateCache(src, dest, basePath) { | ||
if (!src.length) | ||
if (!src.length) { | ||
return; | ||
} | ||
@@ -606,2 +715,7 @@ // Resolve the relative path from basePath to each src file | ||
// make async | ||
var done = currenttask.async(); | ||
var watch; | ||
// setup default options | ||
@@ -638,3 +752,3 @@ var options = currenttask.options({ | ||
} else { | ||
console.warn(('The --removeComments value of "' + options.removeComments + '" ' + 'supercedes the --comments value of ' + options.comments + '"').magenta); | ||
console.warn(('The --removeComments value of "' + options.removeComments + '" ' + 'supercedes the --comments value of "' + options.comments + '"').magenta); | ||
} | ||
@@ -644,16 +758,14 @@ } | ||
// Was the whole process successful | ||
var success = true; | ||
var watch; | ||
// Some interesting logs: | ||
//http://gruntjs.com/api/inside-tasks#inside-multi-tasks | ||
//console.log(this) | ||
//console.log(this.files[0]); // An array of target files ( only one in our case ) | ||
//console.log(this.files[0].src); // a getter for a resolved list of files | ||
//console.log(this.files[0].orig.src); // The original glob / array / !array / <% array %> for files. Can be very fancy :) | ||
// http://gruntjs.com/api/inside-tasks#inside-multi-tasks | ||
// console.log(this) | ||
// console.log(this.files[0]); // An array of target files ( only one in our case ) | ||
// console.log(this.files[0].src); // a getter for a resolved list of files | ||
// console.log(this.files[0].orig.src); // The original glob / array / !array / <% array %> for files. Can be very fancy :) | ||
// NOTE: to access the specified src files we use | ||
// currenttaks.data as that is the raw (non interpolated) string that we reinterpolate ourselves in case the file system as changed since this task was started | ||
// currenttaks.data as that is the raw (non interpolated) string that we reinterpolate ourselves, | ||
// in case the file system as changed since this task was started | ||
// this.files[0] is actually a single in our case as we gave examples of one source / out per target | ||
this.files.forEach(function (target) { | ||
// Run compiler | ||
asyncSeries(this.files, function (target) { | ||
// Create a reference file? | ||
@@ -668,3 +780,3 @@ var reference = target.reference; | ||
function isReferenceFile(filename) { | ||
return path.resolve(filename) == referenceFile; | ||
return path.resolve(filename) === referenceFile; | ||
} | ||
@@ -681,3 +793,3 @@ | ||
function isOutFile(filename) { | ||
return path.resolve(filename) == outFile_d_ts; | ||
return path.resolve(filename) === outFile_d_ts; | ||
} | ||
@@ -694,14 +806,11 @@ | ||
var lastCompile = 0; | ||
// Compiles all the files | ||
// Uses the blind tsc compile task | ||
// logs errors | ||
// Time the whole process | ||
var starttime; | ||
var endtime; | ||
function runCompilation(files, target, options) { | ||
// Don't run it yet | ||
grunt.log.writeln('Compiling...'.yellow); | ||
// Time the task and go | ||
starttime = new Date().getTime(); | ||
// The files to compile | ||
@@ -721,18 +830,21 @@ var filesToCompile = files; | ||
// Time the compiler process | ||
var starttime = new Date().getTime(); | ||
var endtime; | ||
// Compile the files | ||
var result = compileAllFiles(filesToCompile, target, options); | ||
return compileAllFiles(filesToCompile, target, options).then(function (result) { | ||
// End the timer | ||
lastCompile = endtime = new Date().getTime(); | ||
// End the timer | ||
endtime = new Date().getTime(); | ||
// Evaluate the result | ||
if (result.code != 0) { | ||
var msg = "Compilation failed"; | ||
grunt.log.error(msg.red); | ||
return false; | ||
} else { | ||
var time = (endtime - starttime) / 1000; | ||
grunt.log.writeln(('Success: ' + time.toFixed(2) + 's for ' + files.length + ' typescript files').green); | ||
return true; | ||
} | ||
// Evaluate the result | ||
if (!result || result.code) { | ||
grunt.log.error('Compilation failed'.red); | ||
return false; | ||
} else { | ||
var time = (endtime - starttime) / 1000; | ||
grunt.log.writeln(('Success: ' + time.toFixed(2) + 's for ' + files.length + ' typescript files').green); | ||
return true; | ||
} | ||
}); | ||
} | ||
@@ -798,11 +910,12 @@ | ||
// compile, If there are any files to compile! | ||
// Compile, if there are any files to compile! | ||
if (files.length > 0) { | ||
success = runCompilation(files, target, options); | ||
// Create the loader if specified & compiliation succeeded | ||
if (success && !!amdloaderPath) { | ||
var referenceOrder = getReferencesInOrder(referenceFile, referencePath, generatedHtmlFiles); | ||
updateAmdLoader(referenceFile, referenceOrder, amdloaderFile, amdloaderPath, target.outDir); | ||
} | ||
return runCompilation(files, target, options).then(function (success) { | ||
// Create the loader if specified & compiliation succeeded | ||
if (success && !!amdloaderPath) { | ||
var referenceOrder = getReferencesInOrder(referenceFile, referencePath, generatedHtmlFiles); | ||
updateAmdLoader(referenceFile, referenceOrder, amdloaderFile, amdloaderPath, target.outDir); | ||
} | ||
return success; | ||
}); | ||
} else { | ||
@@ -812,13 +925,10 @@ grunt.log.writeln('No files to compile'.red); | ||
} | ||
// Nothing to do | ||
return Promise.resolve(true); | ||
} | ||
// Initial compilation: | ||
filterFilesAndCompile(); | ||
// Watch a folder? | ||
watch = target.watch; | ||
if (!!watch) { | ||
// make async | ||
var done = currenttask.async(); | ||
// A debounced version of compile | ||
@@ -830,9 +940,10 @@ var debouncedCompile = _.debounce(filterFilesAndCompile, 150); | ||
// Only ts and html : | ||
if (!endsWith(filepath.toLowerCase(), '.ts') && !endsWith(filepath.toLowerCase(), '.html')) | ||
if (!endsWith(filepath.toLowerCase(), '.ts') && !endsWith(filepath.toLowerCase(), '.html')) { | ||
return; | ||
} | ||
// Do not run if just ran, behaviour same as grunt-watch | ||
// These are the files our run modified | ||
if ((new Date().getTime() - endtime) <= 100) { | ||
//grunt.log.writeln((' ///' + ' >>' + filepath).grey); | ||
if ((new Date().getTime() - lastCompile) <= 100) { | ||
// grunt.log.writeln((' ///' + ' >>' + filepath).grey); | ||
return; | ||
@@ -867,7 +978,9 @@ } | ||
} | ||
}); | ||
if (!watch) { | ||
return success; | ||
} | ||
return filterFilesAndCompile(); | ||
}).then(function (res) { | ||
// Ignore res? (either logs or throws) | ||
if (!watch) { | ||
done(); | ||
} | ||
}, done); | ||
}); | ||
@@ -874,0 +987,0 @@ } |
453
tasks/ts.ts
@@ -1,5 +0,2 @@ | ||
/// <reference path="../defs/node/node.d.ts"/> | ||
/// <reference path="../defs/grunt/gruntjs.d.ts"/> | ||
/// <reference path="../defs/underscore/underscore.d.ts"/> | ||
/// <reference path="../defs/underscore.string/underscore.string.d.ts"/> | ||
/// <reference path="../defs/tsd.d.ts"/> | ||
@@ -11,2 +8,12 @@ /* | ||
// Typescript imports | ||
import _ = require('underscore'); | ||
import _str = require('underscore.string'); | ||
import path = require('path'); | ||
import fs = require('fs'); | ||
// plain vanilla imports | ||
var pathSeperator = path.sep; | ||
var Promise: typeof Promise = require('es6-promise').Promise; | ||
interface ICompileResult { | ||
@@ -108,7 +115,7 @@ code: number; | ||
*/ | ||
it: R | ||
it: R; | ||
/** | ||
* Time in milliseconds. | ||
*/ | ||
time: number | ||
time: number; | ||
} { | ||
@@ -124,13 +131,81 @@ var starttime = new Date().getTime(); | ||
// Typescript imports | ||
import _ = require('underscore'); | ||
import _str = require('underscore.string'); | ||
import path = require('path'); | ||
import fs = require('fs'); | ||
// plain vanilla imports | ||
var shell = require('shelljs'); | ||
var pathSeperator = path.sep; | ||
/** | ||
* Get a random hex value | ||
* | ||
* @returns {string} hex string | ||
*/ | ||
function getRandomHex(length: number = 16): string { | ||
var name: string = ''; | ||
do { | ||
name += Math.round(Math.random() * Math.pow(16, 8)).toString(16); | ||
} | ||
while (name.length < length); | ||
return name.substr(0, length); | ||
} | ||
/** | ||
* Get a unique temp file | ||
* | ||
* @returns {string} unique-ish path to file in given directory. | ||
* @throws when it cannot create a temp file in the specified directory | ||
*/ | ||
function getTempFile(prefix?: string, dir: string = ''): string { | ||
prefix = (prefix ? prefix + '-' : ''); | ||
var attempts = 100; | ||
do { | ||
var name: string = prefix + getRandomHex(8) + '.tmp.txt'; | ||
var dest: string = path.join(dir, name); | ||
if (!fs.existsSync(dest)) { | ||
return dest; | ||
} | ||
attempts--; | ||
} | ||
while (attempts > 0); | ||
throw 'Cannot create temp file in ' + dir; | ||
} | ||
/** | ||
* Run a map operation async in series (simplified) | ||
*/ | ||
function asyncSeries<U, W>(arr: U[], iter: (item: U) => Promise<W>): Promise<W[]> { | ||
arr = arr.slice(0); | ||
var memo: W[] = []; | ||
// Run one at a time | ||
return new Promise((resolve, reject) => { | ||
var next = () => { | ||
if (arr.length === 0) { | ||
resolve(memo); | ||
return; | ||
} | ||
Promise.cast(iter(arr.shift())).then((res: W) => { | ||
memo.push(res); | ||
next(); | ||
}, reject); | ||
}; | ||
next(); | ||
}); | ||
} | ||
function pluginFn(grunt: IGrunt) { | ||
// Helper | ||
function executeNode(args: string[]): Promise<ICompileResult> { | ||
return new Promise((resolve, reject) => { | ||
grunt.util.spawn({ | ||
cmd: 'node', | ||
args: args | ||
}, (error, result, code) => { | ||
var ret: ICompileResult = { | ||
code: code, | ||
output: String(result) | ||
}; | ||
resolve(ret); | ||
}); | ||
}); | ||
} | ||
///////////////////////////////////////////////////////////////////// | ||
@@ -140,46 +215,52 @@ // tsc handling. | ||
function resolveTypeScriptBinPath(currentPath, depth): string { | ||
var targetPath = path.resolve(__dirname, | ||
(new Array(depth + 1)).join("../../"), | ||
"../node_modules/typescript/bin"); | ||
if (path.resolve(currentPath, "node_modules/typescript/bin").length > targetPath.length) { | ||
return null; | ||
function resolveTypeScriptBinPath(): string { | ||
var ownRoot = path.resolve(path.dirname((module).filename), '..'); | ||
var userRoot = path.resolve(ownRoot, '..', '..'); | ||
var binSub = path.join('node_modules', 'typescript', 'bin'); | ||
if (fs.existsSync(path.join(userRoot, binSub))) { | ||
// Using project override | ||
return path.join(userRoot, binSub); | ||
} | ||
if (fs.existsSync(path.resolve(targetPath, "typescript.js"))) { | ||
return targetPath; | ||
} | ||
return path.join(ownRoot, binSub); | ||
} | ||
return resolveTypeScriptBinPath(currentPath, ++depth); | ||
} | ||
function getTsc(binPath: string): string { | ||
return '"' + binPath + '/' + 'tsc"'; | ||
var pkg = JSON.parse(fs.readFileSync(path.resolve(binPath, '..', 'package.json')).toString()); | ||
grunt.log.writeln('Using tsc v' + pkg.version); | ||
return path.join(binPath, 'tsc'); | ||
} | ||
var eol = grunt.util.linefeed; | ||
var exec = shell.exec; | ||
var cwd = path.resolve("."); | ||
var tsc = getTsc(resolveTypeScriptBinPath(cwd, 0)); | ||
// Blindly runs the tsc task using provided options | ||
function compileAllFiles(files: string[], target: ITargetOptions, task: ITaskOptions): ICompileResult { | ||
function compileAllFiles(files: string[], target: ITargetOptions, task: ITaskOptions): Promise<ICompileResult> { | ||
var cmd: string = files.join(' '); | ||
var args: string[] = files.slice(0); | ||
// boolean options | ||
if (task.sourceMap) | ||
cmd = cmd + ' --sourcemap'; | ||
if (task.declaration) | ||
cmd = cmd + ' --declaration'; | ||
if (task.removeComments) | ||
cmd = cmd + ' --removeComments'; | ||
if (task.noImplicitAny) | ||
cmd = cmd + ' --noImplicitAny'; | ||
if (task.noResolve) | ||
cmd = cmd + ' --noResolve'; | ||
if (task.sourceMap) { | ||
args.push('--sourcemap'); | ||
} | ||
if (task.declaration) { | ||
args.push('--declaration'); | ||
} | ||
if (task.removeComments) { | ||
args.push('--removeComments'); | ||
} | ||
if (task.noImplicitAny) { | ||
args.push('--noImplicitAny'); | ||
} | ||
if (task.noResolve) { | ||
args.push('--noResolve'); | ||
} | ||
// string options | ||
cmd = cmd + ' --target ' + task.target.toUpperCase(); | ||
cmd = cmd + ' --module ' + task.module.toLowerCase(); | ||
args.push('--target', task.target.toUpperCase()); | ||
args.push('--module', task.module.toLowerCase()); | ||
// Target options: | ||
if (target.out) { | ||
cmd = cmd + ' --out ' + target.out; | ||
args.push('--out', target.out); | ||
} | ||
@@ -190,26 +271,42 @@ if (target.outDir) { | ||
} | ||
cmd = cmd + ' --outDir ' + target.outDir; | ||
args.push('--outDir', target.outDir); | ||
} | ||
if (task.sourceRoot) { | ||
cmd = cmd + ' --sourceRoot ' + task.sourceRoot; | ||
args.push('--sourceRoot', task.sourceRoot); | ||
} | ||
if (task.mapRoot) { | ||
cmd = cmd + ' --mapRoot ' + task.mapRoot; | ||
args.push('--mapRoot', task.mapRoot); | ||
} | ||
// Locate a compiler | ||
var tsc = getTsc(resolveTypeScriptBinPath()); | ||
// To debug the tsc command | ||
if (task.verbose) { | ||
console.log(cmd.yellow); | ||
console.log(args.join(' ').yellow); | ||
} | ||
else { | ||
grunt.log.verbose.writeln(cmd.yellow); | ||
grunt.log.verbose.writeln(args.join(' ').yellow); | ||
} | ||
// Create a temp last command file and use that to guide tsc. | ||
// Create a temp last command file and use that to guide tsc. | ||
// Reason: passing all the files on the command line causes TSC to go in an infinite loop. | ||
var tempfilename = 'tscommand.tmp.txt'; | ||
var tscExecCommand = 'node ' + tsc + ' @' + tempfilename; | ||
fs.writeFileSync(tempfilename, cmd); | ||
var tempfilename = getTempFile('tscommand'); | ||
if (!tempfilename) { | ||
throw(new Error('cannot create temp file')); | ||
} | ||
return exec(tscExecCommand); | ||
fs.writeFileSync(tempfilename, args.join(' ')); | ||
// Execute command | ||
return executeNode([tsc , '@' + tempfilename]).then((result: ICompileResult) => { | ||
fs.unlinkSync(tempfilename); | ||
grunt.log.writeln(result.output); | ||
return Promise.cast(result); | ||
}, (err) => { | ||
fs.unlinkSync(tempfilename); | ||
throw err; | ||
}); | ||
} | ||
@@ -241,2 +338,3 @@ | ||
var signatureSectionPosition = 0; | ||
var i; | ||
@@ -252,3 +350,3 @@ // Read the original file if it exists | ||
for (var i = 0; i < lines.length; i++) { | ||
for (i = 0; i < lines.length; i++) { | ||
@@ -259,3 +357,3 @@ var line = _str.trim(lines[i]); | ||
if (_str.include(line, ourSignatureStart)) { | ||
//Wait for the end signature: | ||
// Wait for the end signature: | ||
signatureSectionPosition = i; | ||
@@ -269,3 +367,5 @@ inSignatureSection = true; | ||
} | ||
if (inSignatureSection) continue; | ||
if (inSignatureSection) { | ||
continue; | ||
} | ||
@@ -310,6 +410,6 @@ // store the line | ||
// Return whether the file was changed | ||
if (lines.length == updatedFileLines.length) { | ||
if (lines.length === updatedFileLines.length) { | ||
var updated = false; | ||
for (var i = 0; i < lines.length; i++) { | ||
if (lines[i] != updatedFileLines[i]) { | ||
for (i = 0; i < lines.length; i++) { | ||
if (lines[i] !== updatedFileLines[i]) { | ||
updated = true; | ||
@@ -341,2 +441,3 @@ } | ||
var sortedGeneratedFiles = _.sortBy(generatedFiles); | ||
function isGeneratedFile(filename: string): boolean { | ||
@@ -351,3 +452,3 @@ return _.indexOf(sortedGeneratedFiles, filename, true) !== -1; | ||
var referenceIntro = '/// <reference path="'; | ||
var referenceEnd = '" />'; | ||
// var referenceEnd = '" />'; | ||
@@ -368,3 +469,3 @@ // The section of unordered files | ||
if (_str.include(line, ourSignatureStart)) { | ||
//Wait for the end signature: | ||
// Wait for the end signature: | ||
loopState = ReferenceOrder.unordered; | ||
@@ -413,7 +514,12 @@ } | ||
function sharedStart(array: string[]): string { | ||
if (array.length == 0) throw "Cannot find common root of empty array."; | ||
if (array.length === 0) { | ||
throw 'Cannot find common root of empty array.'; | ||
} | ||
var A = array.slice(0).sort(), | ||
firstWord = A[0], | ||
lastWord = A[A.length - 1]; | ||
if (firstWord === lastWord) return firstWord; | ||
if (firstWord === lastWord) { | ||
return firstWord; | ||
} | ||
else { | ||
@@ -425,3 +531,4 @@ var i = -1; | ||
var lastWordChar = lastWord.charAt(i); | ||
} while (firstWordChar == lastWordChar); | ||
} while (firstWordChar === lastWordChar); | ||
return firstWord.substring(0, i); | ||
@@ -453,3 +560,3 @@ } | ||
else { | ||
grunt.warn("No files in reference file: " + referenceFile); | ||
grunt.warn('No files in reference file: ' + referenceFile); | ||
} | ||
@@ -492,3 +599,3 @@ if (files.before.length > 0) { | ||
//remove ts extension '.ts': | ||
// remove ts extension '.ts': | ||
file = file.substr(0, file.length - 3); | ||
@@ -500,3 +607,3 @@ | ||
// Prepend "./" to prevent "basePath" requirejs setting from interferring: | ||
file = "./" + file; | ||
file = './' + file; | ||
@@ -507,3 +614,4 @@ return file; | ||
} | ||
grunt.log.verbose.writeln("Making files relative to outDir..."); | ||
grunt.log.verbose.writeln('Making files relative to outDir...'); | ||
files.before = makeRelativeToOutDir(files.before); | ||
@@ -581,7 +689,7 @@ files.generated = makeRelativeToOutDir(files.generated); | ||
///////////////////////////////////////////////////////////////////// | ||
// HTML -> TS | ||
///////////////////////////////////////////////////////////////////// | ||
// HTML -> TS | ||
//////////////////////////////////////////////////////////////////// | ||
//html -> js processing functions: | ||
// html -> js processing functions: | ||
// Originally from karma-html2js-preprocessor | ||
@@ -591,3 +699,3 @@ // Refactored nicely in html2js grunt task | ||
// Modified nlReplace to be an empty string | ||
var escapeContent = function (content: string, quoteChar= "'"): string { | ||
var escapeContent = function (content: string, quoteChar= '\''): string { | ||
var quoteRegexp = new RegExp('\\' + quoteChar, 'g'); | ||
@@ -600,3 +708,3 @@ var nlReplace = ''; | ||
function stripBOM(str) { | ||
return 0xFEFF == str.charCodeAt(0) | ||
return 0xFEFF === str.charCodeAt(0) | ||
? str.substring(1) | ||
@@ -606,5 +714,5 @@ : str; | ||
var htmlTemplate = _.template("module <%= modulename %> { export var <%= varname %> = '<%= content %>' } "); | ||
var htmlTemplate = _.template('module <%= modulename %> { export var <%= varname %> = \'<%= content %>\' } '); | ||
// Compile an HTML file to a TS file | ||
// Compile an HTML file to a TS file | ||
// Return the filename. This filename will be required by reference.ts | ||
@@ -620,4 +728,4 @@ function compileHTML(filename: string): string { | ||
// Write the content to a file | ||
var outputfile = filename + ".ts"; | ||
// Write the content to a file | ||
var outputfile = filename + '.ts'; | ||
@@ -628,3 +736,3 @@ fs.writeFileSync(outputfile, fileContent); | ||
///////////////////////////////////////////////////////////////////// | ||
///////////////////////////////////////////////////////////////////// | ||
// AngularJS templateCache | ||
@@ -636,6 +744,7 @@ //////////////////////////////////////////////////////////////////// | ||
function generateTemplateCache(src: string[], dest: string, basePath: string) { | ||
if (!src.length) { | ||
return; | ||
} | ||
if (!src.length) return; | ||
// Resolve the relative path from basePath to each src file | ||
// Resolve the relative path from basePath to each src file | ||
var relativePaths: string[] = _.map(src, (anHtmlFile) => 'text!' + makeReferencePath(basePath, anHtmlFile)); | ||
@@ -670,8 +779,8 @@ var fileNames: string[] = _.map(src, (anHtmlFile) => path.basename(anHtmlFile)); | ||
///////////////////////////////////////////////////////////////////// | ||
// The grunt task | ||
///////////////////////////////////////////////////////////////////// | ||
// The grunt task | ||
//////////////////////////////////////////////////////////////////// | ||
// Note: this function is called once for each target | ||
// so task + target options are a bit blurred inside this function | ||
// so task + target options are a bit blurred inside this function | ||
grunt.registerMultiTask('ts', 'Compile TypeScript files', function() { | ||
@@ -681,3 +790,8 @@ | ||
// setup default options | ||
// make async | ||
var done: grunt.task.AsyncResultCatcher = currenttask.async(); | ||
var watch; | ||
// setup default options | ||
var options = currenttask.options<ITaskOptions>({ | ||
@@ -715,3 +829,3 @@ allowBool: false, | ||
console.warn(('The --removeComments value of "' + options.removeComments + '" ' + | ||
'supercedes the --comments value of ' + options.comments + '"').magenta) | ||
'supercedes the --comments value of "' + options.comments + '"').magenta); | ||
} | ||
@@ -721,21 +835,19 @@ } | ||
// Was the whole process successful | ||
var success = true; | ||
var watch; | ||
// Some interesting logs: | ||
// http://gruntjs.com/api/inside-tasks#inside-multi-tasks | ||
// console.log(this) | ||
// console.log(this.files[0]); // An array of target files ( only one in our case ) | ||
// console.log(this.files[0].src); // a getter for a resolved list of files | ||
// console.log(this.files[0].orig.src); // The original glob / array / !array / <% array %> for files. Can be very fancy :) | ||
// Some interesting logs: | ||
//http://gruntjs.com/api/inside-tasks#inside-multi-tasks | ||
//console.log(this) | ||
//console.log(this.files[0]); // An array of target files ( only one in our case ) | ||
//console.log(this.files[0].src); // a getter for a resolved list of files | ||
//console.log(this.files[0].orig.src); // The original glob / array / !array / <% array %> for files. Can be very fancy :) | ||
// NOTE: to access the specified src files we use | ||
// currenttaks.data as that is the raw (non interpolated) string that we reinterpolate ourselves in case the file system as changed since this task was started | ||
// currenttaks.data as that is the raw (non interpolated) string that we reinterpolate ourselves, | ||
// in case the file system as changed since this task was started | ||
// this.files[0] is actually a single in our case as we gave examples of one source / out per target | ||
this.files.forEach(function (target: ITargetOptions) { | ||
// Run compiler | ||
asyncSeries(this.files, (target: ITargetOptions) => { | ||
// Create a reference file? | ||
// Create a reference file? | ||
var reference = target.reference; | ||
@@ -746,9 +858,9 @@ var referenceFile; | ||
referenceFile = path.resolve(reference); | ||
referencePath = path.dirname(referenceFile) | ||
referencePath = path.dirname(referenceFile); | ||
} | ||
function isReferenceFile(filename: string) { | ||
return path.resolve(filename) == referenceFile; | ||
return path.resolve(filename) === referenceFile; | ||
} | ||
// Create an output file? | ||
// Create an output file? | ||
var out = target.out; | ||
@@ -762,6 +874,6 @@ var outFile; | ||
function isOutFile(filename: string): boolean { | ||
return path.resolve(filename) == outFile_d_ts; | ||
return path.resolve(filename) === outFile_d_ts; | ||
} | ||
// Create an amd loader? | ||
// Create an amd loader? | ||
var amdloader = target.amdloader; | ||
@@ -775,14 +887,12 @@ var amdloaderFile; | ||
// Compiles all the files | ||
var lastCompile = 0; | ||
// Compiles all the files | ||
// Uses the blind tsc compile task | ||
// logs errors | ||
// Time the whole process | ||
var starttime; | ||
var endtime; | ||
function runCompilation(files: string[], target: ITargetOptions, options: ITaskOptions) { | ||
function runCompilation(files: string[], target: ITargetOptions, options: ITaskOptions): Promise<boolean> { | ||
// Don't run it yet | ||
grunt.log.writeln('Compiling...'.yellow); | ||
// Time the task and go | ||
starttime = new Date().getTime(); | ||
// The files to compile | ||
@@ -794,3 +904,3 @@ var filesToCompile = files; | ||
if (!!referencePath && target.out) { | ||
filesToCompile = [referenceFile] | ||
filesToCompile = [referenceFile]; | ||
} | ||
@@ -801,30 +911,33 @@ | ||
// Time the compiler process | ||
var starttime = new Date().getTime(); | ||
var endtime; | ||
// Compile the files | ||
var result = compileAllFiles(filesToCompile, target, options); | ||
return compileAllFiles(filesToCompile, target, options).then((result: ICompileResult) => { | ||
// End the timer | ||
lastCompile = endtime = new Date().getTime(); | ||
// End the timer | ||
endtime = new Date().getTime(); | ||
// Evaluate the result | ||
if (result.code != 0) { | ||
var msg = "Compilation failed"/*+result.output*/; | ||
grunt.log.error(msg.red); | ||
return false; | ||
} | ||
else { | ||
var time = (endtime - starttime) / 1000; | ||
grunt.log.writeln(('Success: ' + time.toFixed(2) + 's for ' + files.length + ' typescript files').green); | ||
return true; | ||
} | ||
// Evaluate the result | ||
if (!result || result.code) { | ||
grunt.log.error('Compilation failed'.red); | ||
return false; | ||
} | ||
else { | ||
var time = (endtime - starttime) / 1000; | ||
grunt.log.writeln(('Success: ' + time.toFixed(2) + 's for ' + files.length + ' typescript files').green); | ||
return true; | ||
} | ||
}); | ||
} | ||
// Find out which files to compile | ||
// Then calls the compile function on those files | ||
// Then calls the compile function on those files | ||
// Also this funciton is debounced | ||
function filterFilesAndCompile() { | ||
function filterFilesAndCompile(): Promise<boolean> { | ||
// Html files: | ||
// Note: | ||
// compile html files before reference file creation. Which is done in runCompilation | ||
// compile html files before globbing the file system again | ||
// Html files: | ||
// Note: | ||
// compile html files before reference file creation. Which is done in runCompilation | ||
// compile html files before globbing the file system again | ||
var generatedHtmlFiles = []; | ||
@@ -835,4 +948,4 @@ if (currenttask.data.html) { | ||
} | ||
// The template cache files do not go into generated files. | ||
// You are free to generate a `ts OR js` file, both should just work | ||
// The template cache files do not go into generated files. | ||
// You are free to generate a `ts OR js` file, both should just work | ||
if (currenttask.data.templateCache) { | ||
@@ -872,3 +985,3 @@ if (!currenttask.data.templateCache.src || !currenttask.data.templateCache.dest || !currenttask.data.templateCache.baseUrl) { | ||
var result = timeIt(() => { | ||
return updateReferenceFile(files, generatedHtmlFiles, referenceFile, referencePath) | ||
return updateReferenceFile(files, generatedHtmlFiles, referenceFile, referencePath); | ||
}); | ||
@@ -880,11 +993,12 @@ if (result.it === true) { | ||
// compile, If there are any files to compile! | ||
// Compile, if there are any files to compile! | ||
if (files.length > 0) { | ||
success = runCompilation(files, target, options); | ||
// Create the loader if specified & compiliation succeeded | ||
if (success && !!amdloaderPath) { | ||
var referenceOrder: IReferences = getReferencesInOrder(referenceFile, referencePath, generatedHtmlFiles); | ||
updateAmdLoader(referenceFile, referenceOrder, amdloaderFile, amdloaderPath, target.outDir); | ||
} | ||
return runCompilation(files, target, options).then((success: boolean) => { | ||
// Create the loader if specified & compiliation succeeded | ||
if (success && !!amdloaderPath) { | ||
var referenceOrder: IReferences = getReferencesInOrder(referenceFile, referencePath, generatedHtmlFiles); | ||
updateAmdLoader(referenceFile, referenceOrder, amdloaderFile, amdloaderPath, target.outDir); | ||
} | ||
return success; | ||
}); | ||
} | ||
@@ -895,31 +1009,28 @@ else { | ||
} | ||
// Nothing to do | ||
return Promise.resolve(true); | ||
} | ||
// Initial compilation: | ||
filterFilesAndCompile(); | ||
// Watch a folder? | ||
// Watch a folder? | ||
watch = target.watch; | ||
if (!!watch) { | ||
// make async | ||
var done: grunt.task.AsyncResultCatcher = currenttask.async(); | ||
// A debounced version of compile | ||
// A debounced version of compile | ||
var debouncedCompile = _.debounce(filterFilesAndCompile, 150); | ||
// local event to handle file event | ||
// local event to handle file event | ||
function handleFileEvent(filepath: string, displaystr: string) { | ||
// Only ts and html : | ||
if (!endsWith(filepath.toLowerCase(), '.ts') && !endsWith(filepath.toLowerCase(), '.html')) | ||
// Only ts and html : | ||
if (!endsWith(filepath.toLowerCase(), '.ts') && !endsWith(filepath.toLowerCase(), '.html')) { | ||
return; | ||
} | ||
// Do not run if just ran, behaviour same as grunt-watch | ||
// These are the files our run modified | ||
if ((new Date().getTime() - endtime) <= 100) { | ||
//grunt.log.writeln((' ///' + ' >>' + filepath).grey); | ||
// Do not run if just ran, behaviour same as grunt-watch | ||
// These are the files our run modified | ||
if ((new Date().getTime() - lastCompile) <= 100) { | ||
// grunt.log.writeln((' ///' + ' >>' + filepath).grey); | ||
return; | ||
} | ||
// Log and run the debounced version. | ||
// Log and run the debounced version. | ||
grunt.log.writeln((displaystr + ' >>' + filepath).yellow); | ||
@@ -929,10 +1040,10 @@ debouncedCompile(); | ||
// get path | ||
// get path | ||
var watchpath = path.resolve(watch); | ||
// create a file watcher for path | ||
// create a file watcher for path | ||
var chokidar = require('chokidar'); | ||
var watcher = chokidar.watch(watchpath, { ignoreInitial: true, persistent: true }); | ||
// Log what we are doing | ||
// Log what we are doing | ||
grunt.log.writeln(('Watching all TypeScript / Html files under : ' + watchpath).cyan); | ||
@@ -946,10 +1057,12 @@ | ||
} | ||
return filterFilesAndCompile(); | ||
}); | ||
if (!watch) { | ||
return success; | ||
} | ||
}).then((res: boolean[]) => { | ||
// Ignore res? (either logs or throws) | ||
if (!watch) { | ||
done(); | ||
} | ||
}, done); | ||
}); | ||
} | ||
export = pluginFn; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
296
128321
8
8
1689
1
+ Addedes6-promise@~0.1.1
+ Addedes6-promise@0.1.2(transitive)
- Removedshelljs@0.1.4
- Removedshelljs@0.1.4(transitive)