├── .jshintrc
├── tests
├── ExplicitlyNamedFilterInModule
│ ├── expected
│ │ ├── MyApp.Area.ng.ts
│ │ ├── toUpper.ts
│ │ └── toUpper.ng.ts
│ └── src
│ │ └── toUpper.ts
├── ImplicitlyNamedFilterInModule
│ ├── expected
│ │ ├── MyApp.Area.ng.ts
│ │ ├── toUpper.ts
│ │ └── toUpper.ng.ts
│ └── src
│ │ └── toUpper.ts
├── MultiNamedDirectiveInModule
│ ├── expected
│ │ ├── MyApp.Area.ng.ts
│ │ ├── MyDirective.ts
│ │ └── MyDirective.ng.ts
│ └── src
│ │ └── MyDirective.ts
├── SingleNamedDirectiveInModule
│ ├── expected
│ │ ├── MyApp.Area.ng.ts
│ │ ├── MyDirective.ts
│ │ └── MyDirective.ng.ts
│ └── src
│ │ └── MyDirective.ts
├── ImplicitServiceInModuleNoDependencies
│ ├── expected
│ │ ├── MyApp.Area.ng.ts
│ │ ├── AService.ts
│ │ └── AService.ng.ts
│ └── src
│ │ └── AService.ts
├── ModuleDefinitionWithModuleDependencies
│ ├── expected
│ │ ├── MyApp.Area.ng.ts
│ │ ├── MyApp.ts
│ │ ├── MyController.ts
│ │ ├── MyApp.ng.ts
│ │ └── MyController.ng.ts
│ └── src
│ │ ├── MyApp.ts
│ │ └── MyController.ts
├── ImplicitControllerInModuleNoDependencies
│ ├── expected
│ │ ├── MyApp.Area.ng.ts
│ │ ├── MyController.ts
│ │ └── MyController.ng.ts
│ └── src
│ │ └── MyController.ts
├── ModuleDefinitionWithModuleNgDependencies
│ ├── src
│ │ └── MyApp.ts
│ └── expected
│ │ ├── MyApp.ts
│ │ └── MyApp.ng.ts
├── ImplicitControllerInModuleNoCtorNoDependencies
│ ├── expected
│ │ ├── MyApp.Area.ng.ts
│ │ ├── MyController.ts
│ │ └── MyController.ng.ts
│ └── src
│ │ └── MyController.ts
├── ImplicitControllerInModuleWithNgServiceDependency
│ ├── expected
│ │ ├── MyApp.Area.ng.ts
│ │ ├── MyController.ts
│ │ └── MyController.ng.ts
│ └── src
│ │ └── MyController.ts
├── ImplicitControllerInModuleWithServiceDependency
│ ├── expected
│ │ ├── MyApp.Area.ng.ts
│ │ ├── MyController.ts
│ │ ├── AService.ts
│ │ ├── MyController.ng.ts
│ │ └── AService.ng.ts
│ └── src
│ │ ├── MyController.ts
│ │ └── AService.ts
├── SingleNamedDirectiveInModuleWithServiceDependency
│ ├── expected
│ │ ├── MyApp.Area.ng.ts
│ │ ├── AService.ts
│ │ ├── MyDirective.ts
│ │ ├── AService.ng.ts
│ │ └── MyDirective.ng.ts
│ └── src
│ │ ├── AService.ts
│ │ └── MyDirective.ts
├── ImplicitServiceWithInterfaceInModuleNoDependencies
│ ├── expected
│ │ ├── MyApp.Area.ng.ts
│ │ ├── AService.ts
│ │ └── AService.ng.ts
│ └── src
│ │ └── AService.ts
├── SingleNamedDirectiveInModuleWithNgServiceDependency
│ ├── expected
│ │ ├── MyApp.Area.ng.ts
│ │ ├── MyDirective.ts
│ │ └── MyDirective.ng.ts
│ └── src
│ │ └── MyDirective.ts
├── ModuleDefinitionWithRunFuncWithNgServiceDependencyAndModuleDependencies
│ ├── src
│ │ ├── MyController.ts
│ │ └── MyApp.ts
│ └── expected
│ │ ├── MyController.ts
│ │ └── MyApp.ts
├── ModuleDefinitionWithRunFuncWithServiceDependencyAndModuleDependencies
│ ├── src
│ │ ├── MyController.ts
│ │ ├── MyApp.ts
│ │ └── AService.ts
│ └── expected
│ │ ├── MyController.ts
│ │ ├── MyApp.ts
│ │ └── AService.ts
├── ModuleDefinitionWithConfigurationMethodWithProviderDependencies
│ ├── src
│ │ └── MyApp.ts
│ └── expected
│ │ ├── MyApp.ts
│ │ └── MyApp.ng.ts
└── compare.js
├── sample
├── app
│ ├── home
│ │ ├── home.html
│ │ └── HomeController.ts
│ ├── components
│ │ ├── hello
│ │ │ └── HelloService.ts
│ │ ├── Greenify
│ │ │ └── GreenifyDirective.ts
│ │ └── TitleCase
│ │ │ └── TitleCaseFilter.ts
│ └── app.ts
├── package.json
├── bower.json
├── index.html
├── tslint.json
└── gruntfile.js
├── .gitignore
├── package.json
├── gruntfile.js
├── README.md
├── LICENSE
└── tasks
└── tsng.js
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "loopfunc": true,
3 | "curly": true
4 | }
--------------------------------------------------------------------------------
/tests/ExplicitlyNamedFilterInModule/expected/MyApp.Area.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | angular.module("MyApp.Area", []);
3 | }
--------------------------------------------------------------------------------
/tests/ImplicitlyNamedFilterInModule/expected/MyApp.Area.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | angular.module("MyApp.Area", []);
3 | }
--------------------------------------------------------------------------------
/tests/MultiNamedDirectiveInModule/expected/MyApp.Area.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | angular.module("MyApp.Area", []);
3 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModule/expected/MyApp.Area.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | angular.module("MyApp.Area", []);
3 | }
--------------------------------------------------------------------------------
/tests/ImplicitServiceInModuleNoDependencies/expected/MyApp.Area.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | angular.module("MyApp.Area", []);
3 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithModuleDependencies/expected/MyApp.Area.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | angular.module("MyApp.Area", []);
3 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithModuleDependencies/src/MyApp.ts:
--------------------------------------------------------------------------------
1 | module MyApp {
2 | var dependencies = [
3 | Area
4 | ];
5 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleNoDependencies/expected/MyApp.Area.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | angular.module("MyApp.Area", []);
3 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithModuleDependencies/expected/MyApp.ts:
--------------------------------------------------------------------------------
1 | module MyApp {
2 | var dependencies = [
3 | Area
4 | ];
5 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithModuleNgDependencies/src/MyApp.ts:
--------------------------------------------------------------------------------
1 | module MyApp {
2 | var dependencies = [
3 | "ngRoute"
4 | ];
5 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleNoCtorNoDependencies/expected/MyApp.Area.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | angular.module("MyApp.Area", []);
3 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleWithNgServiceDependency/expected/MyApp.Area.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | angular.module("MyApp.Area", []);
3 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleWithServiceDependency/expected/MyApp.Area.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | angular.module("MyApp.Area", []);
3 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithModuleNgDependencies/expected/MyApp.ts:
--------------------------------------------------------------------------------
1 | module MyApp {
2 | var dependencies = [
3 | "ngRoute"
4 | ];
5 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModuleWithServiceDependency/expected/MyApp.Area.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | angular.module("MyApp.Area", []);
3 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleNoCtorNoDependencies/src/MyController.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class MyController {
3 |
4 | }
5 | }
--------------------------------------------------------------------------------
/tests/ImplicitServiceWithInterfaceInModuleNoDependencies/expected/MyApp.Area.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | angular.module("MyApp.Area", []);
3 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModuleWithNgServiceDependency/expected/MyApp.Area.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | angular.module("MyApp.Area", []);
3 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleNoCtorNoDependencies/expected/MyController.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class MyController {
3 |
4 | }
5 | }
--------------------------------------------------------------------------------
/sample/app/home/home.html:
--------------------------------------------------------------------------------
1 |
2 |
Home
3 |
{{ vm.message | titlecase }}
4 |
--------------------------------------------------------------------------------
/tests/ImplicitServiceInModuleNoDependencies/src/AService.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class AService {
3 | constructor () {
4 |
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/ImplicitServiceInModuleNoDependencies/expected/AService.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class AService {
3 | constructor () {
4 |
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithModuleDependencies/src/MyController.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class MyController {
3 | constructor () {
4 |
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleNoDependencies/src/MyController.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class MyController {
3 | constructor () {
4 |
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/ImplicitlyNamedFilterInModule/src/toUpper.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 |
3 | //@NgFilter
4 | function toUpper(input: string) {
5 | return input.toUpperCase();
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithModuleDependencies/expected/MyController.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class MyController {
3 | constructor () {
4 |
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleNoDependencies/expected/MyController.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class MyController {
3 | constructor () {
4 |
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/ImplicitlyNamedFilterInModule/expected/toUpper.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 |
3 | //@NgFilter
4 | function toUpper(input: string) {
5 | return input.toUpperCase();
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/ExplicitlyNamedFilterInModule/src/toUpper.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 |
3 | //@NgFilter("toUpper")
4 | function upper(input: string) {
5 | return input.toUpperCase();
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/ExplicitlyNamedFilterInModule/expected/toUpper.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 |
3 | //@NgFilter("toUpper")
4 | function upper(input: string) {
5 | return input.toUpperCase();
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithModuleDependencies/expected/MyApp.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp {
2 | angular.module("MyApp", [
3 | "MyApp.Area",
4 | ]);
5 |
6 | var dependencies = [
7 | Area
8 | ];
9 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithModuleNgDependencies/expected/MyApp.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp {
2 | angular.module("MyApp", [
3 | "ngRoute",
4 | ]);
5 |
6 | var dependencies = [
7 | "ngRoute"
8 | ];
9 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithRunFuncWithNgServiceDependencyAndModuleDependencies/src/MyController.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class MyController {
3 | constructor () {
4 |
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithRunFuncWithServiceDependencyAndModuleDependencies/src/MyController.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class MyController {
3 | constructor () {
4 |
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithRunFuncWithNgServiceDependencyAndModuleDependencies/expected/MyController.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class MyController {
3 | constructor () {
4 |
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithRunFuncWithServiceDependencyAndModuleDependencies/expected/MyController.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class MyController {
3 | constructor () {
4 |
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleWithNgServiceDependency/src/MyController.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class MyController {
3 | constructor (
4 | $location: ng.ILocationService) {
5 |
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleWithNgServiceDependency/expected/MyController.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class MyController {
3 | constructor (
4 | $location: ng.ILocationService) {
5 |
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithRunFuncWithNgServiceDependencyAndModuleDependencies/src/MyApp.ts:
--------------------------------------------------------------------------------
1 | module MyApp {
2 | var dependencies = [
3 | Area
4 | ];
5 |
6 | function run($log: ng.ILogService) {
7 | $log.log("Something");
8 | }
9 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithRunFuncWithNgServiceDependencyAndModuleDependencies/expected/MyApp.ts:
--------------------------------------------------------------------------------
1 | module MyApp {
2 | var dependencies = [
3 | Area
4 | ];
5 |
6 | function run($log: ng.ILogService) {
7 | $log.log("Something");
8 | }
9 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithRunFuncWithServiceDependencyAndModuleDependencies/src/MyApp.ts:
--------------------------------------------------------------------------------
1 | module MyApp {
2 | var dependencies = [
3 | Area
4 | ];
5 |
6 | function run($log: ng.ILogService, aService: Area.IAService) {
7 | $log.log(aService.go());
8 | }
9 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithRunFuncWithServiceDependencyAndModuleDependencies/expected/MyApp.ts:
--------------------------------------------------------------------------------
1 | module MyApp {
2 | var dependencies = [
3 | Area
4 | ];
5 |
6 | function run($log: ng.ILogService, aService: Area.IAService) {
7 | $log.log(aService.go());
8 | }
9 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleWithServiceDependency/src/MyController.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class MyController {
3 | private _aService: Area.IAService
4 |
5 | constructor (aService: Area.IAService) {
6 | this._aService = aService;
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # User-specific files
2 | *.suo
3 | *.user
4 | *.sln.docstates
5 |
6 | # Bower Components
7 | bower_components
8 |
9 | # Node Modules
10 | node_modules
11 |
12 | # js sample files
13 | sample/js
14 |
15 | # Test output
16 | tests/*/actual
17 |
18 | # Processed files
19 | *.ng.ts
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleWithServiceDependency/expected/MyController.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | class MyController {
3 | private _aService: Area.IAService
4 |
5 | constructor (aService: Area.IAService) {
6 | this._aService = aService;
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModule/src/MyDirective.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | //@NgDirective('myDirective')
3 | class MyDirective implements ng.IDirective {
4 | public restrict = "A";
5 |
6 | public link(scope: any, element: ng.IAugmentedJQuery, attrs) {
7 |
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModule/expected/MyDirective.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | //@NgDirective('myDirective')
3 | class MyDirective implements ng.IDirective {
4 | public restrict = "A";
5 |
6 | public link(scope: any, element: ng.IAugmentedJQuery, attrs) {
7 |
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/sample/app/components/hello/HelloService.ts:
--------------------------------------------------------------------------------
1 | module App.Sample.Hello {
2 | export interface IHelloService {
3 | sayHello(): string;
4 | }
5 |
6 | class HelloService implements IHelloService {
7 | public sayHello() {
8 | return "Hello from the HelloService service!";
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/tests/ImplicitlyNamedFilterInModule/expected/toUpper.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 |
5 | //@NgFilter
6 | function toUpper(input: string) {
7 | return input.toUpperCase();
8 | }
9 |
10 | angular.module("MyApp.Area")
11 | .filter("toUpper", () => toUpper);
12 | }
--------------------------------------------------------------------------------
/tests/ExplicitlyNamedFilterInModule/expected/toUpper.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 |
5 | //@NgFilter("toUpper")
6 | function upper(input: string) {
7 | return input.toUpperCase();
8 | }
9 |
10 | angular.module("MyApp.Area")
11 | .filter("toUpper", () => upper);
12 | }
--------------------------------------------------------------------------------
/tests/MultiNamedDirectiveInModule/src/MyDirective.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | //@NgDirective('foo')
3 | //@NgDirective('bar')
4 | class MyDirective implements ng.IDirective {
5 | public restrict = "A";
6 |
7 | public link(scope: any, element: ng.IAugmentedJQuery, attrs) {
8 |
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleNoCtorNoDependencies/expected/MyController.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 | class MyController {
5 |
6 | }
7 |
8 | angular.module("MyApp.Area")
9 | .controller("MyApp.Area.MyController", [
10 | MyController
11 | ]);
12 | }
--------------------------------------------------------------------------------
/tests/MultiNamedDirectiveInModule/expected/MyDirective.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | //@NgDirective('foo')
3 | //@NgDirective('bar')
4 | class MyDirective implements ng.IDirective {
5 | public restrict = "A";
6 |
7 | public link(scope: any, element: ng.IAugmentedJQuery, attrs) {
8 |
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/sample/app/components/Greenify/GreenifyDirective.ts:
--------------------------------------------------------------------------------
1 | module App.Sample.Greenify {
2 |
3 | //@NgDirective('appGreenify')
4 | class GreenifyDirective implements ng.IDirective {
5 | public restrict = "A";
6 |
7 | public link(scope: any, element: ng.IAugmentedJQuery) {
8 | element.css({ color: "#00aa00" });
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleWithServiceDependency/src/AService.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | export interface IAService {
3 | go(): string;
4 | }
5 |
6 | class AService implements IAService {
7 | constructor () {
8 |
9 | }
10 |
11 | public go() {
12 | return "Hello World";
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/tests/ImplicitServiceInModuleNoDependencies/expected/AService.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 | class AService {
5 | constructor () {
6 |
7 | }
8 | }
9 |
10 | angular.module("MyApp.Area")
11 | .service("MyApp.Area.AService", [
12 | AService
13 | ]);
14 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModuleWithServiceDependency/src/AService.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | export interface IAService {
3 | go(): string;
4 | }
5 |
6 | class AService implements IAService {
7 | constructor () {
8 |
9 | }
10 |
11 | public go() {
12 | return "Hello World";
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleWithServiceDependency/expected/AService.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | export interface IAService {
3 | go(): string;
4 | }
5 |
6 | class AService implements IAService {
7 | constructor () {
8 |
9 | }
10 |
11 | public go() {
12 | return "Hello World";
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/tests/ImplicitServiceWithInterfaceInModuleNoDependencies/src/AService.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | export interface IAService {
3 | go(): string;
4 | }
5 |
6 | class AService implements IAService {
7 | constructor () {
8 |
9 | }
10 |
11 | public go() {
12 | return "Hello World";
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModuleWithServiceDependency/expected/AService.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | export interface IAService {
3 | go(): string;
4 | }
5 |
6 | class AService implements IAService {
7 | constructor () {
8 |
9 | }
10 |
11 | public go() {
12 | return "Hello World";
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/sample/app/home/HomeController.ts:
--------------------------------------------------------------------------------
1 | module App.Sample.Home {
2 | interface IHelloViewModel {
3 | message: string;
4 | }
5 |
6 | class HomeController implements IHelloViewModel {
7 | constructor(helloService: Hello.IHelloService) {
8 | this.message = helloService.sayHello();
9 | }
10 |
11 | public message: string;
12 | }
13 | }
--------------------------------------------------------------------------------
/tests/ImplicitServiceWithInterfaceInModuleNoDependencies/expected/AService.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | export interface IAService {
3 | go(): string;
4 | }
5 |
6 | class AService implements IAService {
7 | constructor () {
8 |
9 | }
10 |
11 | public go() {
12 | return "Hello World";
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleNoDependencies/expected/MyController.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 | class MyController {
5 | constructor () {
6 |
7 | }
8 | }
9 |
10 | angular.module("MyApp.Area")
11 | .controller("MyApp.Area.MyController", [
12 | MyController
13 | ]);
14 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithModuleDependencies/expected/MyController.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 | class MyController {
5 | constructor () {
6 |
7 | }
8 | }
9 |
10 | angular.module("MyApp.Area")
11 | .controller("MyApp.Area.MyController", [
12 | MyController
13 | ]);
14 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithRunFuncWithServiceDependencyAndModuleDependencies/src/AService.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | export interface IAService {
3 | go(): string;
4 | }
5 |
6 | class AService implements IAService {
7 | constructor () {
8 |
9 | }
10 |
11 | public go() {
12 | return "Hello World";
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithConfigurationMethodWithProviderDependencies/src/MyApp.ts:
--------------------------------------------------------------------------------
1 | module MyApp {
2 | function configuration($routeProvider: ng.route.IRouteProvider, $logProvider: ng.ILogProvider) {
3 | $logProvider.debugEnabled(true);
4 |
5 | $routeProvider
6 | .when("/", { templateUrl: "tmpl/home.html" })
7 | .otherwise({ redirectTo: "/" });
8 | }
9 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithRunFuncWithServiceDependencyAndModuleDependencies/expected/AService.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | export interface IAService {
3 | go(): string;
4 | }
5 |
6 | class AService implements IAService {
7 | constructor () {
8 |
9 | }
10 |
11 | public go() {
12 | return "Hello World";
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithConfigurationMethodWithProviderDependencies/expected/MyApp.ts:
--------------------------------------------------------------------------------
1 | module MyApp {
2 | function configuration($routeProvider: ng.route.IRouteProvider, $logProvider: ng.ILogProvider) {
3 | $logProvider.debugEnabled(true);
4 |
5 | $routeProvider
6 | .when("/", { templateUrl: "tmpl/home.html" })
7 | .otherwise({ redirectTo: "/" });
8 | }
9 | }
--------------------------------------------------------------------------------
/sample/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sample",
3 | "version": "0.0.0",
4 | "description": "",
5 | "main": "index.html",
6 | "author": "Damian Edwards",
7 | "license": "Apache 2.0",
8 | "devDependencies": {
9 | "grunt": "~0.4.4",
10 | "grunt-tslint": "~0.4.1",
11 | "grunt-typescript": "~0.3.4",
12 | "grunt-contrib-clean": "~0.5.0",
13 | "grunt-contrib-connect": "~0.7.1",
14 | "grunt-contrib-copy": "~0.5.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleWithNgServiceDependency/expected/MyController.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 | class MyController {
5 | constructor (
6 | $location: ng.ILocationService) {
7 |
8 | }
9 | }
10 |
11 | angular.module("MyApp.Area")
12 | .controller("MyApp.Area.MyController", [
13 | "$location",
14 | MyController
15 | ]);
16 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModuleWithServiceDependency/src/MyDirective.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | //@NgDirective('myDirective')
3 | class MyDirective implements ng.IDirective {
4 | private _aService: Area.IAService;
5 |
6 | constructor(aService: Area.IAService) {
7 | this._aService = aService;
8 | }
9 |
10 | public restrict = "A";
11 |
12 | public link(scope: any, element: ng.IAugmentedJQuery, attrs) {
13 |
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModuleWithNgServiceDependency/src/MyDirective.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | //@NgDirective('myDirective')
3 | class MyDirective implements ng.IDirective {
4 | private _window: ng.IWindowService;
5 |
6 | constructor($window: ng.IWindowService) {
7 | this._window = $window;
8 | }
9 |
10 | public restrict = "A";
11 |
12 | public link(scope: any, element: ng.IAugmentedJQuery, attrs) {
13 |
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModuleWithServiceDependency/expected/MyDirective.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | //@NgDirective('myDirective')
3 | class MyDirective implements ng.IDirective {
4 | private _aService: Area.IAService;
5 |
6 | constructor(aService: Area.IAService) {
7 | this._aService = aService;
8 | }
9 |
10 | public restrict = "A";
11 |
12 | public link(scope: any, element: ng.IAugmentedJQuery, attrs) {
13 |
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModuleWithNgServiceDependency/expected/MyDirective.ts:
--------------------------------------------------------------------------------
1 | module MyApp.Area {
2 | //@NgDirective('myDirective')
3 | class MyDirective implements ng.IDirective {
4 | private _window: ng.IWindowService;
5 |
6 | constructor($window: ng.IWindowService) {
7 | this._window = $window;
8 | }
9 |
10 | public restrict = "A";
11 |
12 | public link(scope: any, element: ng.IAugmentedJQuery, attrs) {
13 |
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleWithServiceDependency/expected/MyController.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 | class MyController {
5 | private _aService: Area.IAService
6 |
7 | constructor (aService: Area.IAService) {
8 | this._aService = aService;
9 | }
10 | }
11 |
12 | angular.module("MyApp.Area")
13 | .controller("MyApp.Area.MyController", [
14 | "MyApp.Area.IAService",
15 | MyController
16 | ]);
17 | }
--------------------------------------------------------------------------------
/sample/app/components/TitleCase/TitleCaseFilter.ts:
--------------------------------------------------------------------------------
1 | module App.Sample.TitleCase {
2 |
3 | //@NgFilter('titlecase')
4 | function titleCase(input: string) {
5 | var out = "",
6 | lastChar = "";
7 |
8 | for (var i = 0; i < input.length; i++) {
9 | out = out + (lastChar === " " || lastChar === ""
10 | ? input.charAt(i).toUpperCase()
11 | : input.charAt(i));
12 |
13 | lastChar = input.charAt(i);
14 | }
15 |
16 | return out;
17 | }
18 | }
--------------------------------------------------------------------------------
/sample/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sample",
3 | "version": "0.1.2",
4 | "homepage": "https://github.com/DamianEdwards/grunt-tsng",
5 | "authors": [
6 | "DamianEdwards "
7 | ],
8 | "license": "Apache 2.0",
9 | "private": true,
10 | "ignore": [
11 | "**/.*",
12 | "node_modules",
13 | "bower_components",
14 | "test",
15 | "tests"
16 | ],
17 | "devDependencies": {
18 | "angular": "~1.2.16",
19 | "dt-angular": "~1.2.0",
20 | "angular-route": "~1.2.16"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/tests/ImplicitControllerInModuleWithServiceDependency/expected/AService.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 | export interface IAService {
5 | go(): string;
6 | }
7 |
8 | class AService implements IAService {
9 | constructor () {
10 |
11 | }
12 |
13 | public go() {
14 | return "Hello World";
15 | }
16 | }
17 |
18 | angular.module("MyApp.Area")
19 | .service("MyApp.Area.IAService", [
20 | AService
21 | ]);
22 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModuleWithServiceDependency/expected/AService.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 | export interface IAService {
5 | go(): string;
6 | }
7 |
8 | class AService implements IAService {
9 | constructor () {
10 |
11 | }
12 |
13 | public go() {
14 | return "Hello World";
15 | }
16 | }
17 |
18 | angular.module("MyApp.Area")
19 | .service("MyApp.Area.IAService", [
20 | AService
21 | ]);
22 | }
--------------------------------------------------------------------------------
/tests/ImplicitServiceWithInterfaceInModuleNoDependencies/expected/AService.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 | export interface IAService {
5 | go(): string;
6 | }
7 |
8 | class AService implements IAService {
9 | constructor () {
10 |
11 | }
12 |
13 | public go() {
14 | return "Hello World";
15 | }
16 | }
17 |
18 | angular.module("MyApp.Area")
19 | .service("MyApp.Area.IAService", [
20 | AService
21 | ]);
22 | }
--------------------------------------------------------------------------------
/tests/ModuleDefinitionWithConfigurationMethodWithProviderDependencies/expected/MyApp.ng.ts:
--------------------------------------------------------------------------------
1 | module MyApp {
2 | angular.module("MyApp", [
3 | ]).config([
4 | "$routeProvider",
5 | "$logProvider",
6 | configuration
7 | ]);
8 |
9 | function configuration($routeProvider: ng.route.IRouteProvider, $logProvider: ng.ILogProvider) {
10 | $logProvider.debugEnabled(true);
11 |
12 | $routeProvider
13 | .when("/", { templateUrl: "tmpl/home.html" })
14 | .otherwise({ redirectTo: "/" });
15 | }
16 | }
--------------------------------------------------------------------------------
/sample/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | grunt-tsng Sample
5 |
10 |
11 |
12 | grung-tsng Sample
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/sample/app/app.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | module App.Sample {
5 | var dependencies = [
6 | "ngRoute",
7 | App.Sample.Hello,
8 | App.Sample.TitleCase,
9 | App.Sample.Greenify,
10 | App.Sample.Home
11 | ];
12 |
13 | function configuration($routeProvider: ng.route.IRouteProvider) {
14 | // Configure routes
15 | $routeProvider
16 | .when("/home", { templateUrl: "app/home/home.html" })
17 | .otherwise({ redirectTo: "/home" });
18 | }
19 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModule/expected/MyDirective.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 | //@NgDirective('myDirective')
5 | class MyDirective implements ng.IDirective {
6 | constructor() {
7 | for (var m in this) {
8 | if (this[m].bind) {
9 | this[m] = this[m].bind(this);
10 | }
11 | }
12 | }
13 |
14 | public restrict = "A";
15 |
16 | public link(scope: any, element: ng.IAugmentedJQuery, attrs) {
17 |
18 | }
19 | }
20 |
21 | angular.module("MyApp.Area")
22 | .directive("myDirective", [
23 | function () {
24 | return new MyDirective();
25 | }
26 | ]);
27 | }
--------------------------------------------------------------------------------
/tests/MultiNamedDirectiveInModule/expected/MyDirective.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 | //@NgDirective('foo')
5 | //@NgDirective('bar')
6 | class MyDirective implements ng.IDirective {
7 | constructor() {
8 | for (var m in this) {
9 | if (this[m].bind) {
10 | this[m] = this[m].bind(this);
11 | }
12 | }
13 | }
14 |
15 | public restrict = "A";
16 |
17 | public link(scope: any, element: ng.IAugmentedJQuery, attrs) {
18 |
19 | }
20 | }
21 |
22 | angular.module("MyApp.Area")
23 | .directive("foo", [
24 | function () {
25 | return new MyDirective();
26 | }
27 | ])
28 | .directive("bar", [
29 | function () {
30 | return new MyDirective();
31 | }
32 | ]);
33 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModuleWithNgServiceDependency/expected/MyDirective.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 | //@NgDirective('myDirective')
5 | class MyDirective implements ng.IDirective {
6 | private _window: ng.IWindowService;
7 |
8 | constructor($window: ng.IWindowService) {
9 | for (var m in this) {
10 | if (this[m].bind) {
11 | this[m] = this[m].bind(this);
12 | }
13 | }
14 | this._window = $window;
15 | }
16 |
17 | public restrict = "A";
18 |
19 | public link(scope: any, element: ng.IAugmentedJQuery, attrs) {
20 |
21 | }
22 | }
23 |
24 | angular.module("MyApp.Area")
25 | .directive("myDirective", [
26 | "$window",
27 | function (a) {
28 | return new MyDirective(a);
29 | }
30 | ]);
31 | }
--------------------------------------------------------------------------------
/tests/SingleNamedDirectiveInModuleWithServiceDependency/expected/MyDirective.ng.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module MyApp.Area {
4 | //@NgDirective('myDirective')
5 | class MyDirective implements ng.IDirective {
6 | private _aService: Area.IAService;
7 |
8 | constructor(aService: Area.IAService) {
9 | for (var m in this) {
10 | if (this[m].bind) {
11 | this[m] = this[m].bind(this);
12 | }
13 | }
14 | this._aService = aService;
15 | }
16 |
17 | public restrict = "A";
18 |
19 | public link(scope: any, element: ng.IAugmentedJQuery, attrs) {
20 |
21 | }
22 | }
23 |
24 | angular.module("MyApp.Area")
25 | .directive("myDirective", [
26 | "MyApp.Area.IAService",
27 | function (a) {
28 | return new MyDirective(a);
29 | }
30 | ]);
31 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "grunt-tsng",
3 | "version": "0.1.3",
4 | "description": "A TypeScript pre-processor for AngularJS",
5 | "main": "tsng.js",
6 | "author": {
7 | "name": "Damian Edwards",
8 | "url": "https://github.com/DamianEdwards/"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git://github.com/DamianEdwards/grunt-tsng.git"
13 | },
14 | "bugs": {
15 | "url": "https://github.com/DamianEdwards/grunt-tsng/issues"
16 | },
17 | "licenses": [
18 | {
19 | "type": "Apache-2.0",
20 | "url": "https://github.com/DamianEdwards/grunt-tsng/blob/master/LICENSE"
21 | }
22 | ],
23 | "engines": {
24 | "node": ">= 0.8.0"
25 | },
26 | "peerDependencies": {
27 | "grunt": "~0.4.0"
28 | },
29 | "devDependencies": {
30 | "grunt": "~0.4.4",
31 | "grunt-contrib-jshint": "~0.10.0",
32 | "grunt-contrib-clean": "~0.5.0",
33 | "grunt-typescript": "~0.3.4",
34 | "grunt-contrib-copy": "~0.5.0"
35 | },
36 | "keywords": [
37 | "gruntplugin",
38 | "typescript",
39 | "angular",
40 | "angularjs"
41 | ],
42 | "files": [
43 | "tasks",
44 | "LICENSE"
45 | ]
46 | }
47 |
--------------------------------------------------------------------------------
/sample/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "class-name": true,
4 | "curly": true,
5 | "eofline": false,
6 | "forin": true,
7 | "indent": [true, 4],
8 | "label-position": true,
9 | "label-undefined": true,
10 | "max-line-length": [true, 140],
11 | "no-arg": true,
12 | "no-bitwise": true,
13 | "no-console": [true,
14 | "debug",
15 | "info",
16 | "time",
17 | "timeEnd",
18 | "trace"
19 | ],
20 | "no-construct": true,
21 | "no-debugger": true,
22 | "no-duplicate-key": true,
23 | "no-duplicate-variable": true,
24 | "no-empty": true,
25 | "no-eval": true,
26 | "no-string-literal": true,
27 | "no-trailing-whitespace": true,
28 | "no-unreachable": true,
29 | "one-line": [true,
30 | "check-open-brace",
31 | "check-catch",
32 | "check-else",
33 | "check-whitespace"
34 | ],
35 | "quotemark": [true, "double"],
36 | "radix": true,
37 | "semicolon": true,
38 | "triple-equals": [true, "allow-null-check"],
39 | "variable-name": false,
40 | "whitespace": [true,
41 | "check-branch",
42 | "check-decl",
43 | "check-operator",
44 | "check-separator",
45 | "check-type"
46 | ]
47 | }
48 | }
--------------------------------------------------------------------------------
/sample/gruntfile.js:
--------------------------------------------------------------------------------
1 | /*
2 | * grunt-tsng
3 | * https://github.com/DamianEdwards/grunt-tsng
4 | *
5 | * Copyright (c) 2014 Damian Edwards
6 | * Licensed under the Apache 2.0 License.
7 | */
8 |
9 | module.exports = function(grunt) {
10 | "use strict";
11 |
12 | grunt.initConfig({
13 | connect: {
14 | "static": {
15 | options: {
16 | keepalive: true,
17 | hostname: "localhost",
18 | port: 8001,
19 | open: true
20 | }
21 | }
22 | },
23 | copy: { // This is to work around an issue with the dt-angular bower package https://github.com/dt-bower/dt-angular/issues/4
24 | fix: {
25 | files: {
26 | "bower_components/jquery/jquery.d.ts": ["bower_components/dt-jquery/jquery.d.ts"]
27 | }
28 | }
29 | },
30 | clean: {
31 | options: { force: true },
32 | tsng: ['app/**/*.ng.ts'],
33 | js: ['js/**/*.*']
34 | },
35 | tsng: {
36 | options: {
37 | extension: ".ng.ts"
38 | },
39 | dev: {
40 | files: {
41 | "app": ['app/**/*.ts', "!**/*.ng.ts"]
42 | }
43 | }
44 | },
45 | tslint: {
46 | options: {
47 | configuration: grunt.file.readJSON("tslint.json")
48 | },
49 | files: {
50 | src: ['app/**/*.ts', '!**/*.ng.ts']
51 | }
52 | },
53 | typescript: {
54 | options: {
55 | module: 'amd', // or commonjs
56 | target: 'es5', // or es3
57 | sourcemap: false
58 | },
59 | dev: {
60 | files: {
61 | 'js/app.js': ['app/**/*.ng.ts']
62 | }
63 | }
64 | },
65 | });
66 |
67 | grunt.loadTasks("../tasks");
68 |
69 | grunt.loadNpmTasks("grunt-contrib-copy");
70 | grunt.loadNpmTasks("grunt-contrib-clean");
71 | grunt.loadNpmTasks("grunt-contrib-connect");
72 | grunt.loadNpmTasks("grunt-tslint");
73 | grunt.loadNpmTasks("grunt-typescript");
74 |
75 | grunt.registerTask("sample", ["copy:fix", "build", "connect"]);
76 | grunt.registerTask("build", ["clean", "tslint", "tsng", "typescript"]);
77 | grunt.registerTask("default", ["build"]);
78 | };
--------------------------------------------------------------------------------
/gruntfile.js:
--------------------------------------------------------------------------------
1 | /*
2 | * grunt-tsng
3 | * https://github.com/DamianEdwards/grunt-tsng
4 | *
5 | * Copyright (c) 2014 Damian Edwards
6 | * Licensed under the Apache 2.0 License.
7 | */
8 |
9 | module.exports = function(grunt) {
10 | "use strict";
11 |
12 | grunt.initConfig({
13 | jshint: {
14 | all: [
15 | "Gruntfile.js",
16 | "tests/compare.js",
17 | "tasks/**/*.js"
18 | ],
19 | options: {
20 | jshintrc: ".jshintrc"
21 | }
22 | },
23 | clean: {
24 | test: {
25 | src: ["tests/*/actual"]
26 | }
27 | },
28 | copy: {
29 | test: {
30 | files: [
31 | {
32 | expand: true,
33 | cwd: "tests",
34 | src: "*/src/*.*",
35 | dest: "tests",
36 | rename: function (dest, src) {
37 | var newDest = dest + "/" + src.replace("/src/", "/actual/");
38 | return newDest;
39 | }
40 | }
41 | ]
42 | }
43 | },
44 | tsng: {
45 | options: {
46 | cwd: "tests"
47 | },
48 | test: {
49 | files: [
50 | {
51 | expand: true,
52 | cwd: "tests",
53 | src: ["*/actual/**/*.ts", "!**/*.ng.ts"],
54 | dest: "tests",
55 | rename: function (dest, src) {
56 | var parts = src.split("/");
57 | var testName = parts[0];
58 | var newDest = dest + "/" + testName + "/actual";
59 | return newDest;
60 | }
61 | }
62 | ]
63 | }
64 | },
65 | compare: {
66 | test: {
67 | files: [
68 | {
69 | expand: true,
70 | cwd: "tests",
71 | src: "*/expected",
72 | dest: "tests",
73 | rename: function (dest, src) {
74 | var newDest = dest + "/" + src.replace("/expected", "/actual");
75 | return newDest;
76 | }
77 | }
78 | ]
79 | }
80 | }
81 | });
82 |
83 | grunt.loadTasks("tasks");
84 | grunt.loadTasks("tests");
85 |
86 | grunt.loadNpmTasks("grunt-contrib-jshint");
87 | grunt.loadNpmTasks("grunt-contrib-clean");
88 | grunt.loadNpmTasks("grunt-contrib-copy");
89 | grunt.loadNpmTasks("grunt-typescript");
90 |
91 | grunt.registerTask("test", ["clean:test", "copy:test", "tsng:test", "compare:test"]);
92 |
93 | grunt.registerTask("default", ["jshint", "test"]);
94 | };
--------------------------------------------------------------------------------
/tests/compare.js:
--------------------------------------------------------------------------------
1 | /*
2 | * grunt-tsng
3 | * https://github.com/DamianEdwards/grunt-tsng
4 | *
5 | * Copyright (c) 2014 Damian Edwards
6 | * Licensed under the Apache 2.0 License.
7 | */
8 |
9 | module.exports = function (grunt) {
10 | "use strict";
11 |
12 | var fs = require("fs");
13 | var path = require("path");
14 | var util = require("util");
15 |
16 | grunt.registerMultiTask("compare", "Compares two directories", function () {
17 | grunt.log.writeln("Comparing directories:");
18 | grunt.log.writeln(util.inspect(this.files.map(function (el) { return el.src[0]; })));
19 |
20 | grunt.verbose.writeln("Compare this.files: " + util.inspect(this.files));
21 |
22 | var results = [];
23 |
24 | this.files.every(function (fileset) {
25 | if (fileset.src.length !== 1) {
26 | grunt.log.error("Configured file set must contain just one directory: " + utils.inspect(fileset.src));
27 | return false;
28 | }
29 |
30 | var src = path.resolve(fileset.src[0]);
31 | var dest = path.resolve(fileset.dest);
32 |
33 | if (!grunt.file.isDir(src)) {
34 | grunt.log.error("The configured src path is not a directory: " + src);
35 | return false;
36 | }
37 |
38 | if (!grunt.file.isDir(dest)) {
39 | grunt.log.error("The configured dest path is not a directory: " + dest);
40 | return false;
41 | }
42 |
43 | var result = compareDirs(src, dest);
44 | results.push(result);
45 |
46 | if (result.error) {
47 | return false;
48 | }
49 |
50 | return true;
51 | });
52 |
53 | grunt.verbose.writeln("Results: " + util.inspect(results));
54 |
55 | var errors = results
56 | .map(function(result) {
57 | return result.error;
58 | })
59 | .filter(function(el) {
60 | return el;
61 | });
62 |
63 | if (errors.length) {
64 | grunt.log.error(errors[0]);
65 | return false;
66 | }
67 |
68 | grunt.log.ok("All directories match!");
69 | });
70 |
71 | function compareDirs(dir1, dir2) {
72 | grunt.verbose.writeln(" " + dir1 + " -> " + dir2);
73 |
74 | var dir1Files = [],
75 | dir2Files = [],
76 | error;
77 |
78 | // TODO: Check folder structure first using getDirs
79 |
80 | grunt.file.recurse(dir1, function (abspath, rootdir, subdir, filename) {
81 | dir1Files.push({
82 | abspath: abspath,
83 | rootdir: rootdir,
84 | subdir: subdir,
85 | filename: filename
86 | });
87 | });
88 |
89 | grunt.file.recurse(dir2, function (abspath, rootdir, subdir, filename) {
90 | dir2Files.push({
91 | abspath: abspath,
92 | rootdir: rootdir,
93 | subdir: subdir,
94 | filename: filename
95 | });
96 | });
97 |
98 | //grunt.log.writeln(util.inspect(dir1Files));
99 | //grunt.log.writeln(util.inspect(dir2Files));
100 |
101 | // Compare number of files
102 | if (dir1Files.length !== dir2Files.length) {
103 | return {
104 | error: grunt.util.error("Directories have different file count: \r\n" +
105 | " " + dir1 + ": " + dir1Files.length + "\r\n" +
106 | " " + dir2 + ": " + dir2Files.length)
107 | };
108 | }
109 |
110 | // Compare files
111 | dir1Files.every(function (dir1File, idx) {
112 | var dir2File = dir2Files[idx];
113 | var dir1FileContent, dir2FileContent;
114 |
115 | grunt.verbose.writeln("Comparing files: \r\n" +
116 | " " + util.inspect(dir1File) + "\r\n" +
117 | " " + util.inspect(dir2File));
118 |
119 | // Compare file name
120 | if (dir1File.subdir !== dir2File.subdir || dir1File.filename !== dir2File.filename) {
121 | error = {
122 | error: grunt.util.error("Mismatched file name found: \r\n" +
123 | " " + dir1File.abspath + "\r\n" +
124 | " " + dir2File.abspath)
125 | };
126 | return false;
127 | }
128 |
129 | // Compare file content
130 | dir1FileContent = grunt.file.read(dir1File.abspath);
131 | dir2FileContent = grunt.file.read(dir2File.abspath);
132 | if (dir1FileContent !== dir2FileContent) {
133 | error = {
134 | error: grunt.util.error("Mismatched file content found: \r\n" +
135 | " " + dir1File.abspath + "\r\n" +
136 | " " + dir2File.abspath)
137 | };
138 | return false;
139 | }
140 |
141 | return true;
142 | });
143 |
144 | return error || { };
145 | }
146 |
147 | function getDirs(rootDir) {
148 | return fs.readdirSync(rootDir)
149 | .map(function (file) {
150 | var filePath = path.join(rootDir, file);
151 | if (fs.statSync(filePath).isDirectory()) {
152 | return filePath;
153 | }
154 | })
155 | .filter(function (el) {
156 | return el;
157 | });
158 | }
159 | };
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # grunt-tsng v0.1.3
2 |
3 | > A TypeScript pre-processor for AngularJS.
4 |
5 |
6 | ## Getting Started
7 | This plugin requires Grunt `~0.4.0`
8 |
9 | If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:
10 |
11 | ```shell
12 | npm install grunt-tsng --save-dev
13 | ```
14 |
15 | Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
16 |
17 | ```js
18 | grunt.loadNpmTasks('grunt-tsng');
19 | ```
20 |
21 |
22 | ## Tsng task
23 | _Run this task with the `grunt tsng` command._
24 |
25 | Task targets, files and options may be specified according to the grunt [Configuring tasks](http://gruntjs.com/configuring-tasks) guide.
26 |
27 | This task will analyze the set of TypeScript files fed to it and, based on conventions and comment annotations found, will generate new TypeScript files containing the required AngularJS registration calls. This means you can concentrate on writing your application using typed constructs (modules, classes, interfaces, etc.) and not have to worry about wiring it up to AngularJS as explicit modules and dependencies defined using strings.
28 |
29 | For example, you create a controller in a file called `MyController.ts` like this:
30 | ``` JavaScript
31 | module MyApp {
32 | class MyController {
33 | constructor ($location: ng.ILocationService) {
34 | // Do stuff with $location here
35 |
36 | }
37 | }
38 | }
39 | ```
40 |
41 | and grunt-tsng will create a file called `MyController.ng.ts` like this:
42 | ``` JavaScript
43 | ///
44 | module MyApp {
45 | angular.module("MyApp", [
46 | "$scope",
47 | MyController
48 | ]);
49 |
50 | class MyController {
51 | constructor ($location: ng.ILocationService) {
52 | // Do stuff with $location here
53 |
54 | }
55 | }
56 | }
57 | ```
58 |
59 | ### Options
60 |
61 | #### extension
62 |
63 | Type: `string`
64 | Default: `.ng.ts`
65 |
66 | The file extension to use when generating the TypeScript files you'll eventually compile with the TypeScript compiler.
67 |
68 |
69 | ### Example usage
70 | ``` JavaScript
71 | grunt.initConfig({
72 | tsng: {
73 | all: {
74 | src: ['app/*.ts', '!*.ng.ts'],
75 | dest: 'app'
76 | }
77 | }
78 | });
79 | ```
80 |
81 |
82 | ### Supported conventions & annotations
83 |
84 | Take a look at the [sample](https://github.com/DamianEdwards/grunt-tsng/tree/master/sample) for samples of usage.
85 |
86 | To run the sample locally:
87 | - Open a command prompt
88 | - Clone this repo
89 | - Change to the sample directory
90 | - Run `npm install`
91 | - Run `bower install`
92 | - Run `grunt sample`
93 |
94 | Grunt-tsng uses a number of conventions & comment annotations to discover the parts of your app you want to register with AngularJS. Comment annotations are simply a TS line comment followed by @ and the annotation name and any arguments in a method call fashion, e.g. `//@NgFilter('truncate')`
95 |
96 | Grunt-tsng works best when the following conventions are followed:
97 | - Each item you're creating is in its own file, i.e. one controller per file, one directive per file, etc.
98 | - You use TypeScript constructs for organizing and building your app, e.g. put modules, use classes and interfaces to define your items.
99 | - You compile your TypeScript to a single file per AngularJS app.
100 | - You keep the TypeScript items internal to the modules they're defined in (don't export them). Interfaces for your services and models however should be exported so you can use them from other parts of your app.
101 | - You use the [controller as](http://www.thinkster.io/angularjs/GmI3KetKo6/angularjs-experimental-controller-as-syntax) syntax for binding views to controllers.
102 |
103 | #### Modules
104 | TypeScript modules are tracked and mapped one-to-one with Angular modules. Each TypeScript module you declare will end up as an AngularJS module. To declare a module with dependencies, a config and/or run method, simply put the module in its own file with a `dependencies` array variable, configuration method and/or run method, e.g.:
105 |
106 | ``` JavaScript
107 | module MyApp {
108 | var dependencies = [
109 | "ngRoute",
110 | AnotherModuleInMyApp
111 | ];
112 |
113 | function configuration($routeProvider: ng.IRouteProvider) {
114 | // Configure routes here
115 |
116 | }
117 | }
118 | ```
119 |
120 | Modules that are discovered but for which a dedicated file cannot be found will have a file created (in the configured dest directory) and any other file logically in that module will have a `/// ` element added to the top of it.
121 |
122 |
123 | #### Service dependencies
124 | Function dependencies are discovered automatically for the various types (controllers, services, etc.) and included in the generated registration code. Dependency names starting with a '$' are assumed to be built-in AngularJS services and are included as specified, otherwise the dependency name is resolved against the services discovered in your app files.
125 |
126 |
127 | #### Controllers & Services
128 | Controllers and services are discovered by convention for class names ending in 'Controller' and 'Services' respectively. Dependencies are parsed according to the rules outlined above in Service dependencies.
129 |
130 | Services that implement an interface will be registered with Angular using the full interface name rather than the service class name. This way you can inject them into your controllers by simply taking them as typed constructor arguments and the generated file will register the dependencies with Angular for you.
131 |
132 | HomeController.ts:
133 | ``` JavaScript
134 | module MyApp {
135 | class HomeController {
136 | constructor ($location: ng.ILocationService, aService: IAService) {
137 |
138 | }
139 | }
140 | }
141 | ```
142 |
143 | AService.ts:
144 | ``` JavaScript
145 | module MyApp {
146 | export interface IAService {
147 | do(): string;
148 | }
149 |
150 | class AService implements IAService {
151 | constructor () {
152 |
153 | }
154 |
155 | public do() {
156 | return "Hello";
157 | }
158 | }
159 | }
160 | ```
161 |
162 | You can annotate a controller class with `//@NgController` to explicitly declare it, change its name, or even exclude it completely (this is useful in cases where you don't want to register the controller with Angular itself, e.g. when using the modal service from ui.bootstrap).
163 | ModalController.ts:
164 | ``` JavaScript
165 | module MyApp {
166 | //@NgController(skip=true)
167 | class ModalController {
168 | constructor ($location: ng.ILocationService) {
169 |
170 | }
171 | }
172 | }
173 | ```
174 |
175 | #### Directives
176 | Description to come...
177 |
178 | ``` JavaScript
179 | module MyApp {
180 | interface IPreventSubmitAttributes extends ng.IAttributes {
181 | name: string;
182 | appPreventSubmit: string;
183 | }
184 |
185 | //@NgDirective('appPreventSubmit')
186 | class PreventSubmitDirective implements ng.IDirective {
187 | private _preventSubmit: any;
188 |
189 | constructor() {
190 | this.link = this.link.bind(this);
191 | }
192 |
193 | public restrict = "A";
194 |
195 | public link(scope: any, element: ng.IAugmentedJQuery, attrs: IPreventSubmitAttributes) {
196 | element.submit(e => {
197 | if (scope.$eval(attrs.appPreventSubmit)) {
198 | e.preventDefault();
199 | return false;
200 | }
201 | });
202 | }
203 | }
204 | }
205 | ```
206 |
207 | #### Filters
208 | Description to come...
209 |
210 | ``` JavaScript
211 | module MyApp {
212 | //@NgFilter
213 | function truncate(input: string, length: number) {
214 | if (!input) {
215 | return input;
216 | }
217 |
218 | if (input.length <= length) {
219 | return input;
220 | } else {
221 | return input.substr(0, length).trim() + "…";
222 | }
223 | }
224 | }
225 | ```
226 |
227 |
228 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2014 Damian Edwards
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/tasks/tsng.js:
--------------------------------------------------------------------------------
1 | /*
2 | * grunt-tsng
3 | * https://github.com/DamianEdwards/grunt-tsng
4 | *
5 | * Copyright (c) 2014 Damian Edwards
6 | * Licensed under the Apache 2.0 License.
7 | */
8 |
9 | module.exports = function (grunt) {
10 | "use strict";
11 |
12 | var path = require("path");
13 | var util = require("util");
14 |
15 | var newLine = (process.platform === "win32" ? "\r\n" : "\n");
16 |
17 | grunt.registerMultiTask("tsng", "Generate AngularJS registration blocks based on conventions and annotations in TypeScript files.", function () {
18 |
19 | // this.target is current target
20 | // this.data is config for current target
21 | // this.files is globbed files array for current target
22 |
23 | var options = this.options({
24 | extension: ".ng.ts"
25 | });
26 |
27 | //grunt.log.writeln("Extension path: " + options.extension);
28 |
29 | var overallResult = {
30 | modules: [],
31 | controllers: [],
32 | services: [],
33 | directives: [],
34 | filters: [],
35 | fileTally: 0
36 | };
37 | var error;
38 |
39 | this.files.forEach(function (fileSet, idx) {
40 | var setResult = processSet(fileSet, options);
41 |
42 | if (setResult.error) {
43 | error = setResult.error;
44 | return false;
45 | }
46 |
47 | //logResult(setResult, idx + 1);
48 | sumResult(setResult, overallResult);
49 | });
50 |
51 | if (error) {
52 | grunt.log.error(error);
53 | return;
54 | }
55 |
56 | function sumResult(source, target) {
57 | if (!source || !target) {
58 | return;
59 | }
60 |
61 | for (var key in target) {
62 | if (!target.hasOwnProperty(key) || !source.hasOwnProperty(key)) {
63 | continue;
64 | }
65 |
66 | var targetType = (typeof (target[key])).toLowerCase();
67 | var sourceType = (typeof (source[key])).toLowerCase();
68 |
69 | if (targetType !== sourceType) {
70 | continue;
71 | }
72 |
73 | if (targetType === "number" || targetType === "string") {
74 | target[key] = target[key] + source[key];
75 | } else if (Array.isArray(target[key])) {
76 | target[key] = target[key].concat(source[key]);
77 | }
78 | }
79 | }
80 |
81 | function logResult(result, setId) {
82 | grunt.log.writeln("------------------------------------------");
83 | grunt.log.writeln("File Set #" + setId);
84 | grunt.log.writeln("------------------------------------------");
85 |
86 | grunt.log.writeln("Modules:");
87 | result.modules.forEach(function (module) {
88 | grunt.log.writeln(" " + module.name + (module.file ? " defined in " + module.file + " with " + (module.dependencies ? module.dependencies.length : 0) + " dependencies" : " has no file"));
89 | });
90 |
91 | grunt.log.writeln("Controllers:");
92 | result.controllers.forEach(function (controller) {
93 | grunt.log.writeln(" " + controller.name + " using fn " + controller.fnName + " with " + controller.dependencies.length + " dependencies from " + controller.file);
94 | });
95 |
96 | grunt.log.writeln("Services:");
97 | result.services.forEach(function (service) {
98 | grunt.log.writeln(" " + service.name + " using fn " + service.fnName + " with " + service.dependencies.length + " dependencies from " + service.file);
99 | });
100 |
101 | grunt.log.writeln("Directives:");
102 | result.directives.forEach(function (directive) {
103 | grunt.log.writeln(" " + directive.name + " using fn " + directive.fnName + " with " + directive.dependencies.length + " dependencies from " + directive.file);
104 | });
105 |
106 | grunt.log.writeln("Filters:");
107 | result.filters.forEach(function (filter) {
108 | grunt.log.writeln(" " + filter.name + " using fn " + filter.fnName + " from " + filter.file);
109 | });
110 |
111 | for (var key in result) {
112 | if (key === "fileTally" || !result.hasOwnProperty(key)) {
113 | continue;
114 | }
115 |
116 | var items = result[key];
117 | grunt.log.writeln(items.length + " " + key + " found in " + result.fileTally + " files");
118 | }
119 | }
120 |
121 | function processSet(fileSet, options) {
122 | grunt.verbose.writeln("processSet->fileSet: " + util.inspect(fileSet));
123 |
124 | var result = {
125 | modules: [],
126 | controllers: [],
127 | services: [],
128 | directives: [],
129 | filters: [],
130 | fileTally: 0
131 | };
132 | var modules = {};
133 | var files = {};
134 | var error;
135 | var dest = path.resolve(fileSet.dest);
136 | var moduleName;
137 | var serviceNames;
138 |
139 | grunt.verbose.writeln("dest file path: " + dest);
140 |
141 | fileSet.src.forEach(function (filepath) {
142 | var fileResult = processFile(filepath, dest, options);
143 | fileResult.path = filepath;
144 |
145 | if (fileResult.error) {
146 | error = fileResult.error;
147 | return false;
148 | }
149 |
150 | fileResult.module = mergeModules(fileResult, modules);
151 |
152 | if (!fileResult.module) {
153 | throw new Error("File result for file " + filepath + " doesn't have a module");
154 | }
155 |
156 | if (!fileResult.module.file) {
157 | files[filepath] = fileResult;
158 | }
159 |
160 | sumResult(fileResult, result);
161 | result.modules.push(fileResult.module);
162 | result.fileTally++;
163 | });
164 |
165 | if (error) {
166 | return { error: error };
167 | }
168 |
169 | serviceNames = result.services.map(function (service) {
170 | return service.name;
171 | });
172 |
173 | // Emit module files
174 | var moduleNames = [];
175 | for (moduleName in modules) {
176 | if (!modules.hasOwnProperty(moduleName)) {
177 | continue;
178 | }
179 |
180 | moduleNames.push(modules[moduleName].name);
181 | }
182 |
183 | for (moduleName in modules) {
184 | if (!modules.hasOwnProperty(moduleName)) {
185 | continue;
186 | }
187 |
188 | emitModuleFile(modules[moduleName], dest, moduleNames, serviceNames, options);
189 |
190 | if (!modules[moduleName].file) {
191 | throw new Error("Module " + moduleName + " doesn't have a file");
192 | }
193 | }
194 |
195 | // Emit non-module files
196 | for (var filepath in files) {
197 | if (!files.hasOwnProperty(filepath)) {
198 | continue;
199 | }
200 |
201 | emitFile(files[filepath], serviceNames, options);
202 | }
203 |
204 | return result;
205 | }
206 |
207 | function processFile(filepath, dest, options) {
208 | var result = {
209 | module: null,
210 | controllers: [],
211 | services: [],
212 | directives: [],
213 | filters: []
214 | };
215 | var regex = {
216 | // //@NgModule('moduleName')
217 | // module My.Great.Module {
218 | moduleComment: /^\s*\/\/@NgModule(?:\(?['"]?([\w.]+)['"]?\)?\s*)?$/,
219 | moduleDeclaration: /^\s*(?:export\s+)?module\s*([\w.]*)\s*{\s*$/,
220 |
221 | // //@NgController('controllerName')
222 | // class MyController implements IMyViewModel {
223 | controllerComment: /^\s*\/\/@NgController(?:\(?['"]?([\w]*|skip\=true)['"]?\)?\s*)?$/,
224 | controllerDeclaration: /^\s*(?:export\s+)?class (\w+Controller)\s*/,
225 |
226 | // //@NgService('serviceName')
227 | // class MyService implements IMyService {
228 | serviceComment: /^\s*\/\/@NgService(?:\(?['"]?(\w+)['"]?\)?\s*)?$/,
229 | serviceDeclaration: /^\s*(?:export\s+)?class (\w+Service)\s+(?:implements\s+([\w.]+)\s*{)?/,
230 |
231 | // //@NgDirective('directiveName')
232 | // class MyDirective implements ng.IDirective {
233 | directiveComment: /^\s*\/\/@NgDirective(?:\(?['"]?(\w+)['"]?\)?\s*)?$/,
234 | directiveDeclaration: /^\s*(?:export\s+)?class (\w+Directive)\s+(?:implements\s+(\w.+)\s*{)?/,
235 |
236 | // //@NgFilter('filterName')
237 | // function filter(input: string) {
238 | filterComment: /^\s*\/\/\s*@NgFilter(?:\s*\(\s*['"]?(\w+)['"]?\s*\))?\s*$/,
239 | filterDeclaration: /^\s*function\s*([a-zA-Z_$]+)\s*\([a-zA-Z0-9_$:,\s]*\)/,
240 |
241 | // constructor($window: ng.IWindowService) {
242 | constructor: /constructor\s*\(\s*([^(]*)\s*\)\s*{/,
243 |
244 | closingBrace: /^\s*}\s*$/
245 | };
246 | var content = grunt.file.read(filepath);
247 | var lines = content.split(newLine);
248 | var module, line, matches, state, lastClosingBraceLine, error;
249 | var moduleFile;
250 | var expect = {
251 | anything: 0,
252 | moduleDeclaration: 1,
253 | controllerDeclaration: 2,
254 | serviceDeclaration: 4,
255 | directiveComment: 8,
256 | directiveDeclaration: 16,
257 | filterDeclaration: 32
258 | };
259 | var expecting = expect.anything;
260 |
261 | //debugger;
262 |
263 | for (var i = 0; i < lines.length; i++) {
264 | line = lines[i];
265 |
266 | // Check for closing brace on a line by itself
267 | matches = line.match(regex.closingBrace);
268 | if (matches) {
269 | lastClosingBraceLine = i;
270 | continue;
271 | }
272 |
273 | if (expecting === expect.anything) {
274 | // Check for module comment
275 | matches = line.match(regex.moduleComment);
276 | if (matches) {
277 | expecting = expect.moduleDeclaration;
278 | state = matches;
279 | continue;
280 | }
281 |
282 | // Check for module declaration
283 | matches = line.match(regex.moduleDeclaration);
284 | if (matches) {
285 | if (module) {
286 | // A module is already declared for this file
287 | error = "Error: " + filepath + "(" + i + "): Only one module can be declared per file";
288 | break;
289 | }
290 |
291 | moduleFile = parseModuleFile(filepath);
292 | moduleFile.name = matches[1];
293 | moduleFile.declarationLine = i;
294 | module = moduleFile;
295 |
296 | state = null;
297 | }
298 |
299 | // Check for controller comment
300 | matches = line.match(regex.controllerComment);
301 | if (matches) {
302 | expecting = expect.controllerDeclaration;
303 | state = matches;
304 | continue;
305 | }
306 |
307 | // Check for controller declaration
308 | matches = line.match(regex.controllerDeclaration);
309 | if (matches) {
310 | (function () {
311 | var fnName = matches[1];
312 | var name = (module ? module.name + "." : "") + fnName;
313 | var ctor = parseConstructor(content) || { args: [] };
314 |
315 | result.controllers.push({
316 | module: module,
317 | name: name,
318 | fnName: fnName,
319 | dependencies: ctor.args,
320 | file: filepath,
321 | ctorStartLine: ctor.startLine,
322 | ctorEndLine: ctor.endLine
323 | });
324 | }());
325 | expecting = expect.anything;
326 | continue;
327 | }
328 |
329 | // Check for service comment
330 | matches = line.match(regex.serviceComment);
331 | if (matches) {
332 | expecting = expect.serviceDeclaration;
333 | state = matches;
334 | continue;
335 | }
336 |
337 | // Check for service declaration
338 | matches = line.match(regex.serviceDeclaration);
339 | if (matches) {
340 | (function () {
341 | var className = matches[1];
342 | var interfaceName = matches[2];
343 | var name = (module ? module.name + "." : "") + (interfaceName || className);
344 | var ctor = parseConstructor(content) || { args: [] };
345 |
346 | result.services.push({
347 | module: module,
348 | name: name,
349 | fnName: className,
350 | dependencies: ctor.args,
351 | file: filepath,
352 | ctorStartLine: ctor.startLine,
353 | ctorEndLine: ctor.endLine
354 | });
355 | }());
356 | expecting = expect.anything;
357 | continue;
358 | }
359 |
360 | // Check for directive comment
361 | matches = line.match(regex.directiveComment);
362 | if (matches) {
363 | //debugger;
364 | expecting = expect.directiveComment | expect.directiveDeclaration;
365 | state = { names: [] };
366 | state.names.push(matches[1]);
367 | continue;
368 | }
369 |
370 | // Check for filter comment
371 | matches = line.match(regex.filterComment);
372 | if (matches) {
373 | expecting = expect.filterDeclaration;
374 | state = matches;
375 | continue;
376 | }
377 | }
378 |
379 | if (expecting === expect.moduleDeclaration) {
380 | // Check for module declaration
381 | matches = line.match(regex.moduleDeclaration);
382 | if (matches) {
383 | if (module) {
384 | // A module is already declared for this file
385 | error = "Error: " + filepath + "(" + i + "): Only one module can be declared per file";
386 | break;
387 | }
388 |
389 | moduleFile = parseModuleFile(filepath);
390 | moduleFile.name = state[1] || matches[1];
391 | module = moduleFile;
392 |
393 | state = null;
394 | expecting = expect.anything;
395 | } else {
396 | // A module comment was found but the next line wasn't a module declaration
397 | error = "Error: " + filepath + "(" + i + "): @NgModule must be followed by a TypeScript module declaration, e.g. module My.Module.Name {";
398 | break;
399 | }
400 | }
401 |
402 | if (expecting === expect.controllerDeclaration) {
403 | if (state[1] === "skip=true") {
404 | state = null;
405 | expecting = expect.anything;
406 | continue;
407 | }
408 |
409 | // Check for controller declaration
410 | matches = line.match(regex.controllerDeclaration);
411 | if (matches) {
412 | (function () {
413 | var name = (module ? module.name + "." : "") + (state[1] || matches[1]);
414 | var ctor = parseConstructor(content) || { args: [] };
415 |
416 | result.controllers.push({
417 | module: module,
418 | name: name,
419 | fnName: matches[1],
420 | dependencies: ctor.args,
421 | file: filepath,
422 | startLine: ctor.startLine,
423 | endLine: ctor.endLine
424 | });
425 | }());
426 | expecting = expect.anything;
427 | continue;
428 | } else {
429 | // A controller comment was found but the next line wasn't a controller declaration
430 | error = "Error: " + filepath + "(" + i + "): @NgController must be followed by a TypeScript class declaration ending with 'Controller', e.g. class MyController implements IMyViewModel {";
431 | break;
432 | }
433 | }
434 |
435 | if (expecting === expect.serviceDeclaration) {
436 | // Check for service declaration
437 | matches = line.match(regex.serviceDeclaration);
438 | if (matches) {
439 | (function () {
440 | var className = matches[1];
441 | var interfaceName = matches[2];
442 | var name = (module ? module.name + "." : "") + ((state ? state[1] : null) || interfaceName || className);
443 | var ctor = parseConstructor(content) || { args: [] };
444 |
445 | result.services.push({
446 | module: module,
447 | name: name,
448 | fnName: className,
449 | dependencies: ctor.args,
450 | file: filepath,
451 | ctorStartLine: ctor.startLine,
452 | ctorEndLine: ctor.endLine
453 | });
454 | }());
455 | expecting = expect.anything;
456 | continue;
457 | }
458 | }
459 |
460 | if (expecting & expect.directiveComment) {
461 | // Check for directive comment
462 | matches = line.match(regex.directiveComment);
463 | if (matches) {
464 | expecting = expect.directiveComment | expect.directiveDeclaration;
465 | state.names.push(matches[1]);
466 | continue;
467 | }
468 | }
469 |
470 | if (expecting & expect.directiveDeclaration) {
471 | // Check for directive function
472 | matches = line.match(regex.directiveDeclaration);
473 | if (matches) {
474 | (function () {
475 | var fnName = matches[1];
476 | var ctor = parseConstructor(content) || { args: [] };
477 |
478 | state.names.forEach(function (name) {
479 | result.directives.push({
480 | module: module,
481 | file: filepath,
482 | name: name,
483 | fnName: fnName,
484 | classLine: i,
485 | ctorStartLine: ctor.startLine,
486 | ctorEndLine: ctor.endLine,
487 | dependencies: ctor.args
488 | });
489 | });
490 | }());
491 | expecting = expect.anything;
492 | continue;
493 | }
494 | }
495 |
496 | if (expecting === expect.filterDeclaration) {
497 | // Check for filter function
498 | matches = line.match(regex.filterDeclaration);
499 | if (matches) {
500 | result.filters.push({
501 | module: module,
502 | name: state[1] || matches[1],
503 | fnName: matches[1],
504 | file: filepath
505 | });
506 | state = null;
507 | expecting = expect.anything;
508 | continue;
509 | }
510 | }
511 | }
512 |
513 | // EOF
514 | if (expecting !== expect.anything) {
515 | error = "Error: End of file " + filepath + " reached while expecting " + expecting;
516 | }
517 |
518 | if (error) {
519 | return {
520 | error: error
521 | };
522 | }
523 |
524 | result.closingBraceLine = lastClosingBraceLine;
525 | result.module = module;
526 |
527 | return result;
528 | }
529 |
530 | function parseConstructor(fileContents) {
531 | // Extract details from constructor function
532 | // constructor($window: ng.IWindowService) {
533 | var regex = /constructor\s*\(\s*([^(]*)\s*\)\s*{/;
534 | var matches = fileContents.match(regex);
535 | var result = {};
536 |
537 | if (matches) {
538 | result.args = [];
539 | if (matches[1]) {
540 | matches[1].split(",").forEach(function (arg) {
541 | var argParts = arg.split(":");
542 | var a = { name: argParts[0].trim() };
543 | if (argParts.length > 1) {
544 | a.type = argParts[1].trim();
545 | }
546 | result.args.push(a);
547 | });
548 | }
549 |
550 | // Find line numbers where the constructor function starts/ends
551 | var startIndex = fileContents.indexOf(matches[0]);
552 | var endIndex = startIndex + matches[0].length;
553 |
554 | result.startLine = fileContents.substr(0, startIndex).split(newLine).length - 1;
555 | result.endLine = fileContents.substr(0, endIndex).split(newLine).length - 1;
556 |
557 | return result;
558 | }
559 |
560 | // No constructor found
561 | return null;
562 | }
563 |
564 | function parseModuleFile(filepath) {
565 | var regex = {
566 | dependencies: /var\s+dependencies\s*=\s*\[([\w\s.,"']*)\]/,
567 | // BUG: This finds configuration functions that are commented out
568 | configFn: /function\s*(configuration)\s*\(\s*([\w$:.,\s]*)\s*\)\s*{/,
569 | // BUG: This finds run functions that are commented out
570 | runFn: /function\s*(run)\s*\(\s*([\w$:.,\s]*)\s*\)\s*{/
571 | };
572 | var matches = {};
573 | var result = {};
574 | var content = grunt.file.read(filepath);
575 |
576 | for (var key in regex) {
577 | if (!regex.hasOwnProperty(key)) {
578 | continue;
579 | }
580 |
581 | matches[key] = content.match(regex[key]);
582 | if (matches[key]) {
583 | result.file = filepath;
584 | }
585 | }
586 |
587 | if (!result.file) {
588 | return result;
589 | }
590 |
591 | if (matches.dependencies) {
592 | var arrayMembers = matches.dependencies[1];
593 | var dependencies = [];
594 | if (arrayMembers) {
595 | arrayMembers.split(",").forEach(function (dependency) {
596 | dependency = trim(dependency.trim(), ["\"", "'"]);
597 | dependencies.push(dependency);
598 | });
599 | }
600 | result.dependencies = dependencies;
601 | }
602 |
603 | ["configFn", "runFn"].forEach(function (fn) {
604 | if (matches[fn]) {
605 | var args = matches[fn][2];
606 | var dependencies = [];
607 | if (args) {
608 | args.split(",").forEach(function (arg) {
609 | var parts = arg.split(":");
610 | var dependency = {
611 | name: parts[0].trim()
612 | };
613 |
614 | if (parts[1]) {
615 | dependency.type = parts[1].trim();
616 | }
617 |
618 | dependencies.push(dependency);
619 | });
620 | }
621 | result[fn] = {
622 | fnName: matches[fn][1],
623 | dependencies: dependencies
624 | };
625 | }
626 | });
627 |
628 | return result;
629 | }
630 |
631 | function emitModuleFile(module, dest, moduleNames, serviceNames, options) {
632 | var filepath = "";
633 | var content = "";
634 | var srcLines;
635 |
636 | if (module.file) {
637 | //debugger;
638 | // Module already has a file defined, just add the module registration
639 | filepath = module.file.substr(0, module.file.length - 3) + options.extension;
640 | srcLines = grunt.file.read(module.file).split(newLine);
641 |
642 | //grunt.log.writeln("module.declarationLine=" + module.declarationLine);
643 |
644 | srcLines.forEach(function (line, i) {
645 | if (i === (module.declarationLine + 1)) {
646 |
647 | // Add the module registration
648 | content += indent() + "angular.module(\"" + module.name + "\", [" + newLine;
649 |
650 | if (module.dependencies && module.dependencies.length) {
651 | module.dependencies.forEach(function (d) {
652 | var resolvedDependencyName = resolveTypeName(d, module.name, moduleNames);
653 | content += indent(2) + "\"" + (resolvedDependencyName || d) + "\"," + newLine;
654 | });
655 | }
656 |
657 | content += indent() + "])";
658 |
659 | ["config", "run"].forEach(function (method) {
660 | var fn = module[method + "Fn"];
661 | if (fn) {
662 | content += "." + method + "([" + newLine;
663 | fn.dependencies.forEach(function (d) {
664 | var typeName;
665 | if (d.name.substr(0, 1) === "$") {
666 | typeName = d.name;
667 | } else {
668 | typeName = resolveTypeName(d.type, module.name, serviceNames);
669 | if (!typeName) {
670 | // Couldn't resolve type name
671 | throw new Error("Error: Can't resolve dependency for module function " + module.name + "." + method + " with name " + d.type);
672 | }
673 | }
674 | content += indent(2) + "\"" + typeName + "\"," + newLine;
675 | });
676 | content += indent(2) + fn.fnName + newLine + indent() + "])";
677 | }
678 | });
679 |
680 | content += ";" + newLine + newLine;
681 | }
682 |
683 | content += line;
684 |
685 | if (i < (srcLines.length - 1)) {
686 | content += newLine;
687 | }
688 | });
689 | } else {
690 | // We need to render a whole file
691 | filepath = path.join(dest, module.name + options.extension);
692 | content = "module " + module.name + " {" + newLine;
693 | content += indent() + "angular.module(\"" + module.name + "\", []);" + newLine;
694 | content += "}";
695 | }
696 |
697 | grunt.file.write(filepath, content);
698 | module.file = filepath;
699 | }
700 |
701 | function emitFile(file, serviceNames, options) {
702 | var filepath;
703 | var srcLines;
704 | var content = "";
705 | var module = file.module;
706 |
707 | filepath = file.path.substr(0, file.path.length - 3) + options.extension;
708 | srcLines = grunt.file.read(file.path).split(newLine);
709 |
710 | var emitCtor = false;
711 | if (file.directives.length && !file.directives[0].ctorStartLine) {
712 | emitCtor = true;
713 | }
714 |
715 | srcLines.forEach(function (line, i) {
716 | if (i === 0 && module.file) {
717 | // Add reference to module file
718 | // e.g. ///
719 |
720 | content += "/// " + newLine + newLine;
721 | }
722 |
723 | var emitBind = file.directives.length ?
724 | file.directives[0].ctorEndLine ?
725 | (file.directives[0].ctorEndLine + 1) === i // Line after the ctor declartion ends
726 | : (file.directives[0].classLine + 1) === i // No ctor already, so line after the class declaration
727 | : false;
728 |
729 | if (emitBind) {
730 | if (emitCtor) {
731 | // Need to generate a ctor
732 | content += indent(2) + "constructor() {" + newLine;
733 | }
734 | // Emit function to bind instance methods to 'this'
735 | content += indent(3) + "for (var m in this) {" + newLine;
736 | content += indent(4) + "if (this[m].bind) {" + newLine;
737 | content += indent(5) + "this[m] = this[m].bind(this);" + newLine;
738 | content += indent(4) + "}" + newLine;
739 | content += indent(3) + "}" + newLine;
740 | if (emitCtor) {
741 | // Need to generate a ctor
742 | content += indent(2) + "}" + newLine + newLine;
743 | }
744 | }
745 |
746 | if (i === file.closingBraceLine && module.file) {
747 | content += indent() + newLine;
748 | content += indent() + "angular.module(\"" + module.name + "\")";
749 |
750 | // Register controllers
751 | file.controllers.forEach(function (controller) {
752 | content += newLine;
753 | content += indent(2) + ".controller(\"" + controller.name + "\", [" + newLine;
754 |
755 | if (controller.dependencies && controller.dependencies.length) {
756 | controller.dependencies.forEach(function (d) {
757 | var typeName;
758 | if (d.name.substr(0, 1) === "$") {
759 | typeName = d.name;
760 | } else {
761 | typeName = resolveTypeName(d.type, module.name, serviceNames);
762 | if (!typeName) {
763 | // Couldn't resolve type name
764 | throw new Error("Error: Can't resolve dependency for controller " + controller.name + " with name " + d.type);
765 | }
766 | }
767 | content += indent(3) + "\"" + typeName + "\"," + newLine;
768 | });
769 | }
770 |
771 | content += indent(3) + controller.fnName + newLine;
772 | content += indent(2) + "])";
773 | });
774 |
775 | // Register services
776 | file.services.forEach(function (service) {
777 | content += newLine;
778 | content += indent(2) + ".service(\"" + service.name + "\", [" + newLine;
779 |
780 | if (service.dependencies && service.dependencies.length) {
781 | service.dependencies.forEach(function (d) {
782 | var typeName;
783 | if (d.name.substr(0, 1) === "$") {
784 | typeName = d.name;
785 | } else {
786 | typeName = resolveTypeName(d.type, module.name, serviceNames);
787 | if (!typeName) {
788 | // Couldn't resolve type name
789 | throw new Error("Error: Can't resolve dependency for service " + service.name + " with name " + d.type);
790 | }
791 | }
792 | content += indent(3) + "\"" + typeName + "\"," + newLine;
793 | });
794 | }
795 |
796 | content += indent(3) + service.fnName + newLine;
797 | content += indent(2) + "])";
798 | });
799 |
800 | // Register directives
801 | file.directives.forEach(function (directive) {
802 | content += newLine;
803 | content += indent(2) + ".directive(\"" + directive.name + "\", [" + newLine;
804 |
805 | if (directive.dependencies && directive.dependencies.length) {
806 | directive.dependencies.forEach(function (d) {
807 | var typeName;
808 | if (d.name.substr(0, 1) === "$") {
809 | typeName = d.name;
810 | } else {
811 | typeName = resolveTypeName(d.type, module.name, serviceNames);
812 | if (!typeName) {
813 | // Couldn't resolve type name
814 | throw new Error("Error: Can't resolve dependency for directive " + directive.name + " with name " + d.type);
815 | }
816 | }
817 | content += indent(3) + "\"" + typeName + "\"," + newLine;
818 | });
819 | }
820 |
821 | var alphabet = "abcdefghijklmnopqrstuvwxyz";
822 | alphabet += alphabet.toUpperCase();
823 |
824 | var argList = directive.dependencies.map(function (d, index) {
825 | return alphabet.substr(index, 1);
826 | });
827 |
828 | content += indent(3) + "function (";
829 | content += argList;
830 | content += ") {" + newLine;
831 | content += indent(4) + "return new " + directive.fnName + "(" + argList + ");" + newLine;
832 | content += indent(3) + "}" + newLine;
833 | content += indent(2) + "])";
834 | });
835 |
836 | // Register filters
837 | file.filters.forEach(function (filter) {
838 | content += newLine;
839 | content += indent(2) + ".filter(\"" + filter.name + "\", () => " + filter.fnName + ")";
840 | });
841 |
842 | content += ";" + newLine;
843 | }
844 |
845 | content += line;
846 |
847 | if (i < (srcLines.length - 1)) {
848 | content += newLine;
849 | }
850 | });
851 |
852 | grunt.file.write(filepath, content);
853 | }
854 |
855 | function mergeModules(fileResult, modules) {
856 | var module = fileResult.module;
857 |
858 | if (!module) {
859 | return module;
860 | }
861 |
862 | if (!module.file &&
863 | (!fileResult.controllers || !fileResult.controllers.length) &&
864 | (!fileResult.services || !fileResult.services.length) &&
865 | (!fileResult.directives || !fileResult.directives.length) &&
866 | (!fileResult.filters || !fileResult.filters.length)) {
867 |
868 | //grunt.log.writeln("Module " + module.name + " contains no angular types, skipping file emission");
869 |
870 | // No angular types created, just no-op
871 | return module;
872 | }
873 |
874 | var resolvedModule = module;
875 |
876 | if (modules[module.name]) {
877 | // Existing module
878 | if (module.file) {
879 | if (modules[module.name].file) {
880 | // Error: Module defined in multiple files
881 | throw new Error("tsng: Module '" + module.name + "' defined in multiple files");
882 | }
883 | modules[module.name].file = module.file;
884 | }
885 | resolvedModule = modules[module.name];
886 | } else {
887 | modules[module.name] = module;
888 | }
889 |
890 | return resolvedModule;
891 | }
892 |
893 | function resolveTypeName(name, moduleName, allNames) {
894 | ///
895 | ///
896 | ///
897 |
898 | //debugger;
899 | //grunt.log.writeln(util.inspect({ name: name, moduleName: moduleName, allNames: allNames }));
900 |
901 | var prefix, matchedIndex;
902 | var parts = moduleName.split(".");
903 |
904 | if (parts.length === 1) {
905 | matchedIndex = allNames.indexOf(moduleName + "." + name);
906 | if (matchedIndex >= 0) {
907 | return allNames[matchedIndex];
908 | }
909 | // No match found!
910 | return null;
911 | }
912 |
913 | for (var i = parts.length - 1; i >= 0; i--) {
914 | prefix = "";
915 | parts.forEach(function (part, index) {
916 | if (index <= i) {
917 | prefix += part + ".";
918 | }
919 | });
920 |
921 | matchedIndex = allNames.indexOf(prefix + name);
922 | if (matchedIndex >= 0) {
923 | return allNames[matchedIndex];
924 | }
925 | }
926 |
927 | // No match found!
928 | return null;
929 | }
930 |
931 | function trim(target, chars) {
932 | ///
933 | ///
934 |
935 | //debugger;
936 |
937 | var result, i, c;
938 |
939 | chars = chars || [" "];
940 |
941 | if (!target) {
942 | return target;
943 | }
944 |
945 | result = "";
946 |
947 | // Trim from start
948 | for (i = 0; i < target.length; i++) {
949 | c = target[i];
950 | if (chars.indexOf(c) < 0) {
951 | result = target.substr(i);
952 | break;
953 | }
954 | }
955 |
956 | // Trim from end
957 | for (i = result.length - 1; i >= 0; i--) {
958 | c = result[i];
959 | if (chars.indexOf(c) < 0) {
960 | result = result.substring(0, i + 1);
961 | break;
962 | }
963 | }
964 |
965 | return result;
966 | }
967 |
968 | function indent(length, char) {
969 | length = length || 1; // Default to 1 level of indent
970 | char = char || " "; // Default to 4 spaces
971 | var result = "";
972 | for (var i = 0; i < length; i++) {
973 | result += char;
974 | }
975 | return result;
976 | }
977 | });
978 | };
--------------------------------------------------------------------------------