├── .gitattributes ├── .gitignore ├── .travis.yml ├── Angular2-Haxe.hxproj ├── LICENSE ├── README.md ├── bin ├── css │ ├── style.css │ └── style.min.css ├── img │ └── haxe-logo.png ├── index.html └── templates │ └── dependency.tpl.html ├── build.bat ├── build.sh ├── haxelib.json ├── package.json ├── spec ├── CompiledComponents.test.js ├── ComponentMetadata.spec.js ├── DirectiveMetadata.spec.js ├── ViewMetadata.spec.js └── runTests.js └── src ├── BuildRegistry.hx ├── Main.hx ├── angular2haxe ├── AngularExtension.hx ├── Annotation.hx ├── AnnotationExtension.hx ├── AnnotationPair.hx ├── Application.hx ├── ComponentAnnotationExtension.hx ├── DirectiveAnnotationExtension.hx ├── KeyboardEvent.hx ├── LifecycleEventExtension.hx ├── Trace.hx ├── ViewAnnotationExtension.hx ├── ViewEncapsulationExtension.hx ├── buildplugin │ └── BuildPlugin.hx └── ng │ ├── Angular.hx │ ├── ComponentConstructorData.hx │ ├── ComponentMetadata.hx │ ├── DirectiveConstructorData.hx │ ├── DirectiveMetadata.hx │ ├── EventEmitter.hx │ ├── LifecycleEvent.hx │ ├── NgFor.hx │ ├── NgIf.hx │ ├── ViewConstructorData.hx │ ├── ViewEncapsulation.hx │ └── ViewMetadata.hx ├── test ├── ChildComponent.hx ├── Dependency.hx ├── DependencyDisplayComponent.hx ├── DisplayComponent.hx ├── FriendsService.hx ├── HelloWorld.hx ├── InputDirective.hx ├── ParentComponent.hx └── TodoList.hx └── testcompile ├── ChildComponent.hx ├── Dependency.hx ├── DependencyDisplayComponent.hx ├── DisplayComponent.hx ├── FriendsService.hx ├── Greeter.hx ├── HelloWorld.hx ├── InputDirective.hx ├── MyDirective.hx ├── NeedsGreeter.hx ├── NgModelDirective.hx ├── ParentComponent.hx └── TodoList.hx /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.zip 2 | node_modules/ 3 | bin/angular.sfx.dev.js 4 | bin/http.sfx.dev.js 5 | bin/angular2haxe.js 6 | bin/Angular2-Haxe.js 7 | bin/angular2haxe.js.map 8 | bin/Angular2-Haxe.js.map 9 | 10 | # Windows image file caches 11 | Thumbs.db 12 | ehthumbs.db 13 | 14 | # Folder config file 15 | Desktop.ini 16 | 17 | # Recycle Bin used on file shares 18 | $RECYCLE.BIN/ 19 | 20 | # Windows Installer files 21 | *.cab 22 | *.msi 23 | *.msm 24 | *.msp 25 | 26 | # Windows shortcuts 27 | *.lnk 28 | 29 | # ========================= 30 | # Operating System Files 31 | # ========================= 32 | 33 | # OSX 34 | # ========================= 35 | 36 | .DS_Store 37 | .AppleDouble 38 | .LSOverride 39 | 40 | # Thumbnails 41 | ._* 42 | 43 | # Files that might appear on external disk 44 | .Spotlight-V100 45 | .Trashes 46 | 47 | # Directories potentially created on remote AFP share 48 | .AppleDB 49 | .AppleDesktop 50 | Network Trash Folder 51 | Temporary Items 52 | .apdisk 53 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "iojs" 4 | before_install: 5 | - "npm install mocha -g" 6 | - curl http://haxe.org/website-content/downloads/3.2.0/downloads/haxe-3.2.0-linux64.tar.gz > haxe.tar.gz 7 | - tar -xzf haxe.tar.gz -C ~ 8 | - export HAXE_STD_PATH=~/haxe-3.2.0/std 9 | - export HAXE_HOME=~/haxe-3.2.0 10 | - chmod +x ./build.sh 11 | - chmod +x ~/haxe-3.2.0/haxe 12 | script: ./build.sh -------------------------------------------------------------------------------- /Angular2-Haxe.hxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /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 {yyyy} {name of copyright owner} 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Haxe Language Bindings for Angular 2 2 | === 3 | [![Build Status](https://travis-ci.org/nweedon/angular2haxe.svg?branch=master)](https://travis-ci.org/nweedon/angular2haxe) 4 | [![Haxelib](https://img.shields.io/github/tag/nweedon/angular2haxe.svg?style=flat&label=haxelib)](http://lib.haxe.org/p/angular2haxe/) 5 | 6 | * Supported Angular 2 version: alpha.35 7 | * Heavily work-in-progress, API is subject to change as the Angular 2 API goes through development. 8 | 9 | ### Haxelib Installation 10 | * Stable: ```haxelib install angular2haxe 0.3.2``` 11 | 12 | Also, add ```-lib angular2haxe``` to the build command of your project. 13 | 14 | ### Building the demo project 15 | Run ```build.bat``` on Windows or ```./build.sh``` on Linux. This will build a demo project and run 16 | the current suite of tests. You can then launch a webserver targetting the build folder and visit 17 | the servers' configured address to view a selection of demo components. 18 | 19 | *Note:* Currently, you must have an active internet connection for the tests to run correctly, 20 | as the demo webpage accesses the Angular 2 library files. 21 | 22 | ### Building components at build-time *(as of 0.3.0)* 23 | Use the ```@:build``` component metadata to build the component 24 | at build-time. All classes (except for Angular externs) will be resolved 25 | at build-time so that the component does not have to be fully resolved when 26 | the web page loads. 27 | 28 | *Change from 0.3.0-alpha*: All components can now be bootstrapped via the 29 | main class (see example below). The old way of compiling components will still work. 30 | 31 | *Note:* for class names to resolve at build-time, the class needs to be imported. To 32 | solve this, the library utilises a build registry, which holds all imports you want to 33 | resolve. This doesn't come with the library by default, you must provide this yourself; if 34 | you don't know how to do this, I recommend looking at BuildRegistry.hx. 35 | 36 | Finally, to use the build registry, include the following on the command line: 37 | ```-D using_registry``` 38 | 39 | Example: 40 | ```haxe 41 | @:build(angular2haxe.buildplugin.BuildPlugin.app([ 42 | testcompile.DisplayComponent, 43 | testcompile.TodoList, 44 | // ... other class names (as strings or class names, fully qualified) 45 | ])) 46 | class Main 47 | { 48 | static function main() 49 | { 50 | ... 51 | } 52 | } 53 | ``` 54 | 55 | ### Creating an application 56 | Creating an application this way allows you to import and bootstrap all of your components with ease. All data transformation (from Haxe metadata to Angular annotations) is done under the hood! (See 'src/Main.hx'). 57 | ```haxe 58 | import angular2haxe.Application; 59 | 60 | class Main 61 | { 62 | static function main() 63 | { 64 | new Application([ 65 | 66 | // List of class names which are Angular 2 components 67 | 68 | ]); 69 | } 70 | } 71 | ``` 72 | 73 | ### Creating a component (@Component and @View annotations) 74 | Creating components is pretty much the same as it is in ES6/TypeScript, with a few slight changes due to limitations with Haxe metadata. 75 | 76 | **Currently tested metadata for @Component annotation:** 77 | * selector 78 | * lifecycle ("onInit", "onCheck", "onAllChangesDone") 79 | * hostInjector *(Note: class names must be surrounded in double-quotes)* 80 | * compileChildren 81 | 82 | **Implemented but untested metadata for @Component annotation:** 83 | * lifecycle (onChange, onDestroy) 84 | 85 | *Make sure to use the @:expose metadata tag on classes you wish to import!* 86 | 87 | **Currently tested metadata for @View annotation:** 88 | * directives *(Note: class names must be surrounded in double-quotes)* 89 | * template 90 | * templateUrl 91 | 92 | ```haxe 93 | @Component({ 94 | selector: 'display', 95 | viewBindings: ["test.FriendsService"] 96 | }) 97 | @View({ 98 | directives: ["angular.NgFor", "angular.NgIf"], 99 | template: '

My name: {{ myName }}

Friends:

You have many friends!

' 100 | }) 101 | class DisplayComponent 102 | { 103 | public function new(?friends : FriendsService) 104 | { 105 | // ... 106 | } 107 | } 108 | ``` 109 | 110 | ### Creating a directive (@Directive annotation) 111 | Creating a directive is again similar to the way components and views are created with Haxe. View the example below, which injects a service (via component-level injection) into the directive. 112 | 113 | **Currently tested metadata for @Directive annotation:** 114 | * selector 115 | * hostInjector *(Note: class names must be surrounded in double-quotes)* 116 | * properties 117 | * lifecycle ("onInit", "onCheck", "onAllChangesDone") 118 | 119 | **Implemented but untested metadata for @Directive annotation:** 120 | * lifecycle (onChange, onDestroy) 121 | 122 | ```haxe 123 | @:expose 124 | class Greeter 125 | { 126 | public function new() { } 127 | public function greet(name : String) 128 | { 129 | return 'Hello ${name}!'; 130 | } 131 | } 132 | 133 | @Directive({ 134 | selector: 'needs-greeter', 135 | bindings: [ 136 | "test.Greeter" 137 | ] 138 | }) 139 | @:expose 140 | class NeedsGreeter 141 | { 142 | private var greeter : Greeter; 143 | 144 | public function new(greeter : Greeter) 145 | { 146 | this.greeter = greeter; 147 | } 148 | } 149 | ``` 150 | -------------------------------------------------------------------------------- /bin/css/style.css: -------------------------------------------------------------------------------- 1 | html, body 2 | { 3 | width: 100%; 4 | } 5 | 6 | body 7 | { 8 | margin: 0px; 9 | color: #000000; 10 | font-family: 'Open Sans', sans-serif; 11 | 12 | /* Reference: haxe.org */ 13 | background-color: rgb(168,75,56); 14 | background-repeat: no-repeat; 15 | /* Safari 4-5, Chrome 1-9 */ 16 | background: -webkit-gradient(radial, 50% 80%, 0, center center, 100, from(rgb(183,77,49)), to(rgb(100,33,38))); 17 | /* Safari 5.1+, Chrome 10+ */ 18 | background: -webkit-radial-gradient(50% 80%, circle, rgb(183,77,49), rgb(100,33,38)); 19 | /* Firefox 3.6+ */ 20 | background: -moz-radial-gradient(50% 80%, circle, rgb(183,77,49), rgb(100,33,38)); 21 | /* IE 10 */ 22 | background: -ms-radial-gradient(50% 80%, circle, rgb(183,77,49), rgb(100,33,38)); 23 | } 24 | 25 | h1, h3 26 | { 27 | -webkit-margin-before: 5px; 28 | -webkit-margin-after: 5px; 29 | } 30 | 31 | body > div 32 | { 33 | padding: 8px; 34 | } 35 | 36 | body > .examples > div > *:nth-child(2) 37 | { 38 | margin: 8px; 39 | padding: 8px; 40 | display: block; 41 | border: 2px solid rgb(234, 130, 32); 42 | border-radius: 5px; 43 | background-color: rgba(255, 255, 255, 0.3); 44 | } 45 | 46 | div.titlebar 47 | { 48 | background-color: #000000; 49 | color: #FFFFFF; 50 | } 51 | 52 | /* 53 | Force div elements to surround 54 | their children. (Clearfix) 55 | Reference: https://css-tricks.com/snippets/css/clear-fix/ 56 | */ 57 | .examples > div:before, .examples > div:after, .examples > div > *:before, .examples > div > *:after 58 | { 59 | visibility: hidden; 60 | display: block; 61 | font-size: 0; 62 | content: "."; 63 | clear: both; 64 | height: 0; 65 | } 66 | 67 | .haxe-logo 68 | { 69 | float: left; 70 | position: relative; 71 | width: 25px; 72 | height: 25px; 73 | top: 3px; 74 | } 75 | 76 | h3.title 77 | { 78 | position: relative; 79 | left: 10px; 80 | width: 90%; 81 | } 82 | 83 | small 84 | { 85 | color: rgb(234, 130, 32); 86 | } 87 | 88 | footer 89 | { 90 | background-color: #000000; 91 | color: #FFFFFF; 92 | padding: 8px; 93 | } 94 | 95 | footer > a 96 | { 97 | color: #FFFFFF; 98 | text-decoration: none; 99 | font-weight: bold; 100 | } -------------------------------------------------------------------------------- /bin/css/style.min.css: -------------------------------------------------------------------------------- 1 | html,body{width:100%;} 2 | body{margin:0px;color:#000000;font-family:'Open Sans',sans-serif;background-color:rgb(168,75,56);background-repeat:no-repeat;background:-webkit-gradient(radial,50% 80%,0,center center,100,from(rgb(183,77,49)),to(rgb(100,33,38)));background:-webkit-radial-gradient(50% 80%,circle,rgb(183,77,49),rgb(100,33,38));background:-moz-radial-gradient(50% 80%,circle,rgb(183,77,49),rgb(100,33,38));background:-ms-radial-gradient(50% 80%,circle,rgb(183,77,49),rgb(100,33,38));} 3 | h1,h3{-webkit-margin-before:5px;-webkit-margin-after:5px;} 4 | body>div{padding:8px;} 5 | body>.examples>div>*:nth-child(2){margin:8px;padding:8px;display:block;border:2px solid rgb(234,130,32);border-radius:5px;background-color:rgba(255,255,255,0.3);} 6 | div.titlebar{background-color:#000000;color:#FFFFFF;} 7 | .examples>div:before,.examples>div:after,.examples>div>*:before,.examples>div>*:after{visibility:hidden;display:block;font-size:0;content:".";clear:both;height:0;} 8 | .haxe-logo{float:left;position:relative;width:25px;height:25px;top:3px;} 9 | h3.title{position:relative;left:10px;width:90%;} 10 | small{color:rgb(234,130,32);} 11 | footer{background-color:#000000;color:#FFFFFF;padding:8px;} 12 | footer>a{color:#FFFFFF;text-decoration:none;font-weight:bold;} -------------------------------------------------------------------------------- /bin/img/haxe-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nweedon/angular2haxe/5829422d4e377f0c07cbfdccfc18ff81e18b0a30/bin/img/haxe-logo.png -------------------------------------------------------------------------------- /bin/index.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | angular2haxe 21 | 22 | 42 | 43 | 44 | 45 | 46 | 47 |
48 | 49 |

angular2haxe Examples

50 |
51 | 52 | 53 |
54 |
55 | HelloWorld.hx 56 | 57 |
58 | 59 | 60 |
61 | Dependency.hx and DependencyDisplayComponent.hx 62 | 63 |
64 | 65 | 66 |
67 | ParentComponent.hx and ChildComponent.hx 68 | 69 |
70 | 71 | 72 |
73 | TodoList.hx 74 | 75 |
76 | 77 | 78 |
79 | DisplayComponent.hx 80 | 81 |
82 | 83 |
84 | HelloWorld.hx 85 | 86 |
87 | 88 | 89 |
90 | Dependency.hx and DependencyDisplayComponent.hx 91 | 92 |
93 | 94 | 95 |
96 | ParentComponent.hx and ChildComponent.hx 97 | 98 |
99 | 100 | 101 |
102 | TodoList.hx 103 | 104 |
105 | 106 | 107 |
108 | DisplayComponent.hx 109 | 110 |
111 |
112 | 113 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /bin/templates/dependency.tpl.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | View console output for result 4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
-------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | @echo OFF 2 | 3 | haxe -debug --each -cp src -js ./bin/angular2haxe.js -D using_registry -D debug_level=ERROR -main Main -dce full 4 | mocha spec/runTests.js -t 5000 -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #/usr/bin/env sh 2 | ~/haxe-3.2.0/haxe -debug --each -cp src -js ./bin/angular2haxe.js -D using_registry -D debug_level=ERROR -main Main -dce full 3 | mocha spec/runTests.js -t 5000 -------------------------------------------------------------------------------- /haxelib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "angular2haxe", 3 | "url" : "https://github.com/nweedon/angular2haxe", 4 | "license" : "Apache", 5 | "tags" : ["angular", "web", "language bindings"], 6 | "description" : "Haxe language bindings for Angular 2", 7 | "version" : "0.3.2", 8 | "classpath" : "angular2haxe/", 9 | "releasenote" : "Improve code block modification at build-time for app compilation.", 10 | "contributors" : ["nweedon"], 11 | "dependencies" : { } 12 | } 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "connect": "^3.4.0", 4 | "expect.js": "^0.3.1", 5 | "serve-static": "^1.10.0", 6 | "zombie": "^4.0.13" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /spec/CompiledComponents.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | "use strict" 17 | module.exports = { }; 18 | 19 | module.exports.spec = function(browser, expect, compiled) { 20 | let desc = 'Bootstrapped Component Testing'; 21 | 22 | if(compiled) { 23 | desc += " (Compiled)"; 24 | } 25 | 26 | describe(desc, function() { 27 | before(function(done) { 28 | browser.visit('/index.html', { debug: false }, function() { 29 | done(); 30 | }); 31 | }); 32 | 33 | let ns = 'test'; 34 | let componentSuffixes = [ 35 | "ChildComponent", 36 | "DependencyDisplayComponent", 37 | "DisplayComponent", 38 | "HelloWorld", 39 | "ParentComponent", 40 | "TodoList" 41 | ]; 42 | 43 | if(compiled) { 44 | ns += 'compile'; 45 | } 46 | 47 | for(var suffix of componentSuffixes) { 48 | it(`${suffix}`, function() { 49 | expect(browser.window[ns][suffix].__bootstrapped).not.to.be(null); 50 | expect(browser.window[ns][suffix].__bootstrapped).not.to.be(undefined); 51 | expect(browser.window[ns][suffix].__bootstrapped).to.be.a('boolean'); 52 | expect(browser.window[ns][suffix].__bootstrapped).to.eql(true); 53 | }); 54 | } 55 | }); 56 | }; -------------------------------------------------------------------------------- /spec/ComponentMetadata.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | "use strict" 17 | module.exports = { }; 18 | 19 | module.exports.spec = function(browser, expect, compiled) { 20 | let desc = 'ComponentMetadata parsing'; 21 | 22 | if(compiled) { 23 | desc += ' (Compiled)'; 24 | } 25 | 26 | describe(desc, function() { 27 | let meta = { }; 28 | let anno = { }; 29 | let params = { }; 30 | let alreadyConstructed = { }; 31 | 32 | before(function(done) { 33 | browser.visit('/index.html', { debug: false }, function() { 34 | let ns = 'test'; 35 | let packs = ["HelloWorld", "TodoList"]; 36 | 37 | if(compiled) { 38 | ns += 'compile'; 39 | } 40 | 41 | for(var pack of packs) { 42 | anno[pack] = browser.window[ns][pack].annotations; 43 | params[pack] = browser.window[ns][pack].parameters; 44 | alreadyConstructed[pack] = browser.window[ns][pack].__alreadyConstructed; 45 | 46 | if(!compiled) { 47 | meta[pack] = browser.window[ns][pack].__meta__.obj; 48 | } 49 | } 50 | 51 | done(); 52 | }); 53 | }); 54 | 55 | // Selector conversion. 56 | // Should be one-to-one mapping (String -> String) 57 | it('selector', function() { 58 | var expectedSelector; 59 | 60 | if(!compiled) { 61 | expect(meta["HelloWorld"].Component.length).to.eql(1); 62 | expectedSelector = 'greet'; 63 | } else { 64 | expect(alreadyConstructed["HelloWorld"]).to.be.a('boolean'); 65 | expect(alreadyConstructed["HelloWorld"]).to.eql(true); 66 | expectedSelector = 'c-greet'; 67 | } 68 | 69 | expect(anno["HelloWorld"].length).to.eql(2); 70 | expect(anno["HelloWorld"][0]).not.to.be(null); 71 | expect(anno["HelloWorld"][0].selector).not.to.be(null); 72 | expect(anno["HelloWorld"][0].selector).to.eql(expectedSelector); 73 | }); 74 | 75 | // Properties conversion. 76 | // Should be Array -> Array mapping 77 | it('properties', function() { 78 | if(!compiled) { 79 | expect(meta["TodoList"].Component[0].properties).not.to.be(null); 80 | expect(meta["TodoList"].Component[0].properties).to.be.an('array'); 81 | expect(meta["TodoList"].Component[0].properties).to.eql([ "lastValue", "todos" ]); 82 | } else { 83 | expect(alreadyConstructed["TodoList"]).to.be.a('boolean'); 84 | expect(alreadyConstructed["TodoList"]).to.eql(true); 85 | } 86 | 87 | expect(anno["TodoList"][0].properties).not.to.be(null); 88 | expect(anno["TodoList"][0].properties).to.be.an('array'); 89 | expect(anno["TodoList"][0].properties).to.eql([ "lastValue", "todos" ]); 90 | }); 91 | 92 | it('events'); 93 | 94 | // Host conversion. 95 | // Should be Map -> Map 96 | // angular2haxe removes prefixed $__hx__ from keys that are strings. 97 | it('host'); 98 | 99 | // Lifecycle conversion. 100 | // Should be Array -> Array 101 | it('lifecycle', function() { 102 | // Meta checks 103 | if(!compiled) { 104 | expect(meta["TodoList"].Component[0].lifecycle).not.to.be(null); 105 | expect(meta["TodoList"].Component[0].lifecycle.length).to.eql(4); 106 | expect(meta["TodoList"].Component[0].lifecycle).to.eql([ 107 | "onInit", 108 | "onChange", 109 | "onAllChangesDone", 110 | "onCheck" 111 | ]); 112 | } else { 113 | expect(alreadyConstructed["TodoList"]).to.be.a('boolean'); 114 | expect(alreadyConstructed["TodoList"]).to.eql(true); 115 | } 116 | 117 | // Annotation checks 118 | expect(anno["TodoList"]).not.to.be(null); 119 | expect(anno["TodoList"].length).to.eql(2); 120 | expect(anno["TodoList"][0]).not.to.be(null); 121 | expect(anno["TodoList"][0].lifecycle).not.to.be(null); 122 | expect(anno["TodoList"][0].lifecycle.length).to.eql(4); 123 | expect(anno["TodoList"][0].lifecycle).to.eql([ 124 | browser.window.ng.LifecycleEvent.onInit, 125 | browser.window.ng.LifecycleEvent.onChange, 126 | browser.window.ng.LifecycleEvent.onAllChangesDone, 127 | browser.window.ng.LifecycleEvent.onCheck 128 | ]); 129 | }); 130 | 131 | // Bindings conversion. 132 | // Should be String -> Function mapping 133 | it('bindings'); 134 | 135 | // ExportAs conversion. 136 | // Should be String -> String mapping 137 | it('exportAs', function() { 138 | if(!compiled) { 139 | expect(meta["HelloWorld"].Component[0].exportAs).not.to.be(null); 140 | expect(meta["HelloWorld"].Component[0].exportAs).to.be.a('string'); 141 | expect(meta["HelloWorld"].Component[0].exportAs).to.eql('componentGreet'); 142 | } else { 143 | expect(alreadyConstructed["HelloWorld"]).to.be.a('boolean'); 144 | expect(alreadyConstructed["HelloWorld"]).to.eql(true); 145 | } 146 | 147 | expect(anno["HelloWorld"][0].exportAs).not.to.be(null); 148 | expect(anno["HelloWorld"][0].exportAs).to.be.a('string'); 149 | expect(anno["HelloWorld"][0].exportAs).to.eql('componentGreet'); 150 | }); 151 | 152 | // CompileChildren conversion. (Defaults to true) 153 | // Should be Bool -> Bool mapping 154 | it('compileChildren', function() { 155 | expect(anno["HelloWorld"][0].compileChildren).not.to.be(null); 156 | expect(anno["HelloWorld"][0].compileChildren).to.be.a('boolean'); 157 | expect(anno["HelloWorld"][0].compileChildren).to.eql(true); 158 | }); 159 | 160 | it('viewBindings', function() { 161 | var expectedName; 162 | 163 | // Original Metadata 164 | if(!compiled) { 165 | expect(meta["HelloWorld"].Component.length).to.eql(1); 166 | expect(meta["HelloWorld"].Component[0].viewBindings.length).to.eql(1); 167 | expect(meta["HelloWorld"].Component[0].viewBindings[0]).to.be.a('string'); 168 | expect(meta["HelloWorld"].Component[0].viewBindings[0]).to.eql('test.Greeter'); 169 | expectedName = ["test", "Greeter"]; 170 | } else { 171 | expect(alreadyConstructed["HelloWorld"]).to.be.a('boolean'); 172 | expect(alreadyConstructed["HelloWorld"]).to.eql(true); 173 | expectedName = ["testcompile", "Greeter"]; 174 | } 175 | 176 | expect(anno["HelloWorld"].length).to.eql(2); 177 | expect(anno["HelloWorld"][0]).not.to.be(null); 178 | expect(anno["HelloWorld"][0].viewBindings).not.to.be(null); 179 | expect(anno["HelloWorld"][0].viewBindings.length).to.eql(1); 180 | expect(anno["HelloWorld"][0].viewBindings[0]).to.be.a('function'); 181 | expect(anno["HelloWorld"][0].viewBindings[0].__name__).to.eql(expectedName); 182 | }); 183 | 184 | // CompileChildren conversion. (Defaults to "DEFAULT") 185 | // Should be String -> String mapping 186 | it('changeDetection', function() { 187 | if(!compiled) { 188 | expect(meta["TodoList"].Component.length).to.eql(1); 189 | expect(meta["TodoList"].Component[0].changeDetection).not.to.be(null); 190 | expect(meta["TodoList"].Component[0].changeDetection).to.be.a('string'); 191 | expect(meta["TodoList"].Component[0].changeDetection).to.eql('CHECK_ALWAYS'); 192 | } else { 193 | expect(alreadyConstructed["TodoList"]).to.be.a('boolean'); 194 | expect(alreadyConstructed["TodoList"]).to.eql(true); 195 | } 196 | 197 | expect(anno["HelloWorld"][0].changeDetection).not.to.be(null); 198 | expect(anno["HelloWorld"][0].changeDetection).to.be.a('string'); 199 | expect(anno["HelloWorld"][0].changeDetection).to.eql('DEFAULT'); 200 | expect(anno["TodoList"][0].changeDetection).not.to.be(null); 201 | expect(anno["TodoList"][0].changeDetection).to.be.a('string'); 202 | expect(anno["TodoList"][0].changeDetection).to.eql('CHECK_ALWAYS'); 203 | }); 204 | }); 205 | 206 | }; -------------------------------------------------------------------------------- /spec/DirectiveMetadata.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | "use strict" 17 | module.exports = { }; 18 | 19 | module.exports.spec = function(browser, expect, compiled) { 20 | let desc = 'DirectiveMetadata parsing'; 21 | 22 | if(compiled) { 23 | desc += ' (Compiled)'; 24 | } 25 | 26 | describe(desc, function() { 27 | let meta = { }; 28 | let anno = { }; 29 | let params = { }; 30 | let alreadyConstructed = { }; 31 | 32 | before(function(done) { 33 | browser.visit('/index.html', { debug: false }, function() { 34 | let ns = 'test'; 35 | let packs = ["NeedsGreeter", "InputDirective", "Dependency"]; 36 | 37 | if(compiled) { 38 | ns += 'compile'; 39 | } 40 | 41 | for(var pack of packs) { 42 | anno[pack] = browser.window[ns][pack].annotations; 43 | params[pack] = browser.window[ns][pack].parameters; 44 | alreadyConstructed[pack] = browser.window[ns][pack].__alreadyConstructed; 45 | 46 | if(!compiled) { 47 | meta[pack] = browser.window[ns][pack].__meta__.obj; 48 | } 49 | } 50 | 51 | done(); 52 | }); 53 | }); 54 | 55 | // Selector conversion. 56 | // Should be one-to-one mapping (String -> String) 57 | it('selector', function() { 58 | if(!compiled) { 59 | expect(meta["NeedsGreeter"].Directive.length).to.eql(1); 60 | } else { 61 | // Check the component actually built properly at run-time. 62 | expect(alreadyConstructed["NeedsGreeter"]).to.be.a('boolean'); 63 | expect(alreadyConstructed["NeedsGreeter"]).to.eql(true); 64 | } 65 | 66 | expect(anno["NeedsGreeter"].length).to.eql(1); 67 | expect(anno["NeedsGreeter"][0]).not.to.be(null); 68 | expect(anno["NeedsGreeter"][0].selector).not.to.be(null); 69 | 70 | if(!compiled) { 71 | expect(anno["NeedsGreeter"][0].selector).to.eql('needs-greeter'); 72 | } else { 73 | expect(anno["NeedsGreeter"][0].selector).to.eql('c-needs-greeter'); 74 | } 75 | }); 76 | 77 | // Properties conversion. 78 | // Should be Array -> Array mapping 79 | it('properties', function() { 80 | if(!compiled) { 81 | expect(meta["Dependency"].Directive[0].properties).not.to.be(null); 82 | expect(meta["Dependency"].Directive[0].properties).to.be.an('array'); 83 | expect(meta["Dependency"].Directive[0].properties).to.eql([ "id: dependency" ]); 84 | } else { 85 | expect(alreadyConstructed["Dependency"]).to.be.a('boolean'); 86 | expect(alreadyConstructed["Dependency"]).to.eql(true); 87 | } 88 | 89 | expect(anno["Dependency"][0].properties).not.to.be(null); 90 | expect(anno["Dependency"][0].properties).to.be.an('array'); 91 | 92 | if(compiled) { 93 | expect(anno["Dependency"][0].properties).to.eql([ "id: c-dependency" ]); 94 | } else { 95 | expect(anno["Dependency"][0].properties).to.eql([ "id: dependency" ]); 96 | } 97 | }); 98 | 99 | it('events'); 100 | 101 | // Host conversion. 102 | // Should be Map -> Map 103 | // angular2haxe removes prefixed $__hx__ from keys that are strings. 104 | it('host', function() { 105 | if(!compiled) { 106 | expect(meta["InputDirective"].Directive[0].host).not.to.be(null); 107 | expect(meta["InputDirective"].Directive[0].host['(keyup)']).not.to.be(null); 108 | expect(meta["InputDirective"].Directive[0].host['(keyup)']).to.eql('onKeyUp($event)'); 109 | } else { 110 | expect(alreadyConstructed["InputDirective"]).to.be.a('boolean'); 111 | expect(alreadyConstructed["InputDirective"]).to.eql(true); 112 | } 113 | 114 | expect(anno["InputDirective"]).not.to.be(null); 115 | expect(anno["InputDirective"].length).to.eql(1); 116 | expect(anno["InputDirective"][0]).not.to.be(null); 117 | expect(anno["InputDirective"][0].host).not.to.be(null); 118 | expect(anno["InputDirective"][0].host['(keyup)']).not.to.be(null); 119 | expect(anno["InputDirective"][0].host['(keyup)']).to.eql('onKeyUp($event)'); 120 | }); 121 | 122 | // Lifecycle conversion. 123 | // Should be Array -> Array 124 | it('lifecycle', function() { 125 | // Meta checks 126 | if(!compiled) { 127 | expect(meta["InputDirective"].Directive[0].lifecycle).not.to.be(null); 128 | expect(meta["InputDirective"].Directive[0].lifecycle.length).to.eql(4); 129 | expect(meta["InputDirective"].Directive[0].lifecycle).to.eql([ 130 | "onInit", 131 | "onChange", 132 | "onAllChangesDone", 133 | "onCheck" 134 | ]); 135 | } else { 136 | expect(alreadyConstructed["InputDirective"]).to.be.a('boolean'); 137 | expect(alreadyConstructed["InputDirective"]).to.eql(true); 138 | } 139 | 140 | // Annotation checks 141 | expect(anno["InputDirective"]).not.to.be(null); 142 | expect(anno["InputDirective"].length).to.eql(1); 143 | expect(anno["InputDirective"][0]).not.to.be(null); 144 | expect(anno["InputDirective"][0].lifecycle).not.to.be(null); 145 | expect(anno["InputDirective"][0].lifecycle.length).to.eql(4); 146 | expect(anno["InputDirective"][0].lifecycle).to.eql([ 147 | browser.window.ng.LifecycleEvent.onInit, 148 | browser.window.ng.LifecycleEvent.onChange, 149 | browser.window.ng.LifecycleEvent.onAllChangesDone, 150 | browser.window.ng.LifecycleEvent.onCheck 151 | ]); 152 | }); 153 | 154 | // Bindings conversion. 155 | // Should be String -> Function mapping 156 | it('bindings', function() { 157 | var expectedName; 158 | // Original Metadata 159 | if(!compiled) { 160 | expect(meta["NeedsGreeter"].Directive.length).to.eql(1); 161 | expect(meta["NeedsGreeter"].Directive[0].bindings.length).to.eql(1); 162 | expect(meta["NeedsGreeter"].Directive[0].bindings[0]).to.be.a('string'); 163 | expect(meta["NeedsGreeter"].Directive[0].bindings[0]).to.eql('test.Greeter'); 164 | expectedName = ["test", "Greeter"]; 165 | } else { 166 | expect(alreadyConstructed["NeedsGreeter"]).to.be.a('boolean'); 167 | expect(alreadyConstructed["NeedsGreeter"]).to.eql(true); 168 | expectedName = ["testcompile", "Greeter"]; 169 | } 170 | 171 | expect(anno["NeedsGreeter"].length).to.eql(1); 172 | expect(anno["NeedsGreeter"][0]).not.to.be(null); 173 | expect(anno["NeedsGreeter"][0].bindings).not.to.be(null); 174 | expect(anno["NeedsGreeter"][0].bindings.length).to.eql(1); 175 | expect(anno["NeedsGreeter"][0].bindings[0]).to.be.a('function'); 176 | expect(anno["NeedsGreeter"][0].bindings[0].__name__).to.eql(expectedName); 177 | }); 178 | 179 | // ExportAs conversion. 180 | // Should be String -> String mapping 181 | it('exportAs', function() { 182 | if(!compiled) { 183 | expect(meta["InputDirective"].Directive[0].exportAs).not.to.be(null); 184 | expect(meta["InputDirective"].Directive[0].exportAs).to.be.a('string'); 185 | expect(meta["InputDirective"].Directive[0].exportAs).to.eql('input-directive'); 186 | } else { 187 | expect(alreadyConstructed["InputDirective"]).to.be.a('boolean'); 188 | expect(alreadyConstructed["InputDirective"]).to.eql(true); 189 | } 190 | 191 | expect(anno["InputDirective"][0].exportAs).not.to.be(null); 192 | expect(anno["InputDirective"][0].exportAs).to.be.a('string'); 193 | expect(anno["InputDirective"][0].exportAs).to.eql('input-directive'); 194 | }); 195 | 196 | // CompileChildren conversion. (Defaults to true) 197 | // Should be Bool -> Bool mapping 198 | it('compileChildren', function() { 199 | expect(anno["InputDirective"][0].compileChildren).not.to.be(null); 200 | expect(anno["InputDirective"][0].compileChildren).to.be.a('boolean'); 201 | expect(anno["InputDirective"][0].compileChildren).to.eql(true); 202 | }); 203 | }); 204 | 205 | }; -------------------------------------------------------------------------------- /spec/ViewMetadata.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | "use strict" 17 | module.exports = { }; 18 | 19 | module.exports.spec = function(browser, expect, compiled) { 20 | let desc = 'ViewMetadata parsing'; 21 | 22 | if(compiled) { 23 | desc += ' (Compiled)'; 24 | } 25 | 26 | describe(desc, function() { 27 | let meta = { }; 28 | let anno = { }; 29 | let params = { }; 30 | let alreadyConstructed = { }; 31 | 32 | before(function(done) { 33 | browser.visit('/index.html', { debug: false }, function() { 34 | let ns = 'test'; 35 | let packs = ["HelloWorld", "TodoList", "DependencyDisplayComponent"]; 36 | 37 | if(compiled) { 38 | ns += 'compile'; 39 | } 40 | 41 | for(var pack of packs) { 42 | anno[pack] = browser.window[ns][pack].annotations; 43 | params[pack] = browser.window[ns][pack].parameters; 44 | alreadyConstructed[pack] = browser.window[ns][pack].__alreadyConstructed; 45 | 46 | if(!compiled) { 47 | meta[pack] = browser.window[ns][pack].__meta__.obj; 48 | } 49 | } 50 | 51 | done(); 52 | }); 53 | }); 54 | 55 | // TemplateUrl conversion. 56 | // Should be String -> String mapping 57 | it('templateUrl', function() { 58 | if(!compiled) { 59 | expect(meta["DependencyDisplayComponent"].View.length).to.eql(1); 60 | expect(meta["DependencyDisplayComponent"].View[0].templateUrl).not.to.be(null); 61 | expect(meta["DependencyDisplayComponent"].View[0].templateUrl).to.be.a('string'); 62 | expect(meta["DependencyDisplayComponent"].View[0].templateUrl).to.eql("templates/dependency.tpl.html"); 63 | } else { 64 | expect(alreadyConstructed["DependencyDisplayComponent"]).to.be.a('boolean'); 65 | expect(alreadyConstructed["DependencyDisplayComponent"]).to.eql(true); 66 | } 67 | 68 | expect(anno["DependencyDisplayComponent"].length).to.eql(2); 69 | expect(anno["DependencyDisplayComponent"][1]).not.to.be(null); 70 | expect(anno["DependencyDisplayComponent"][1].templateUrl).not.to.be(null); 71 | expect(anno["DependencyDisplayComponent"][1].templateUrl).to.be.a('string'); 72 | expect(anno["DependencyDisplayComponent"][1].templateUrl).to.eql("templates/dependency.tpl.html"); 73 | }); 74 | 75 | // Template conversion. 76 | // Should be one-to-one mapping (String -> String) 77 | it('template', function() { 78 | if(!compiled) { 79 | expect(meta["HelloWorld"].View.length).to.eql(1); 80 | expect(meta["HelloWorld"].View[0].template).not.to.be(null); 81 | expect(meta["HelloWorld"].View[0].template).to.be.a('string'); 82 | expect(meta["HelloWorld"].View[0].template).to.eql("{{ greeter.greet('World') }}"); 83 | } else { 84 | expect(alreadyConstructed["HelloWorld"]).to.be.a('boolean'); 85 | expect(alreadyConstructed["HelloWorld"]).to.eql(true); 86 | } 87 | 88 | expect(anno["HelloWorld"].length).to.eql(2); 89 | expect(anno["HelloWorld"][1]).not.to.be(null); 90 | expect(anno["HelloWorld"][1].template).not.to.be(null); 91 | expect(anno["HelloWorld"][1].template).to.be.a('string'); 92 | 93 | if(compiled) { 94 | expect(anno["HelloWorld"][1].template).to.eql("{{ greeter.greet('World') }}"); 95 | } else { 96 | expect(anno["HelloWorld"][1].template).to.eql("{{ greeter.greet('World') }}"); 97 | } 98 | }); 99 | 100 | // Directives conversion. 101 | it('directives', function() { 102 | var expectedNames = null; 103 | 104 | if(!compiled) { 105 | expectedNames = ["test.Dependency", "test.MyDirective", "test.NgModelDirective"]; 106 | expect(meta["DependencyDisplayComponent"].View.length).to.eql(1); 107 | expect(meta["DependencyDisplayComponent"].View[0].directives).not.to.be(null); 108 | expect(meta["DependencyDisplayComponent"].View[0].directives).to.be.an('array'); 109 | expect(meta["DependencyDisplayComponent"].View[0].directives).to.eql(expectedNames); 110 | } else { 111 | expectedNames = ["testcompile.Dependency", "testcompile.MyDirective", "testcompile.NgModelDirective"]; 112 | expect(alreadyConstructed["DependencyDisplayComponent"]).to.be.a('boolean'); 113 | expect(alreadyConstructed["DependencyDisplayComponent"]).to.eql(true); 114 | } 115 | 116 | for(var name in expectedNames) { 117 | expectedNames[name] = expectedNames[name].split('.'); 118 | } 119 | 120 | expect(anno["DependencyDisplayComponent"].length).to.eql(2); 121 | expect(anno["DependencyDisplayComponent"][1].directives).not.to.be(null); 122 | expect(anno["DependencyDisplayComponent"][1].directives).to.be.an('array'); 123 | 124 | for(var i in expectedNames) { 125 | expect(anno["DependencyDisplayComponent"][1].directives[i]).to.be.a('function'); 126 | expect(anno["DependencyDisplayComponent"][1].directives[i].__name__).to.eql(expectedNames[i]); 127 | } 128 | }); 129 | 130 | // Encapsulation conversion. 131 | it('encapsulation', function() { 132 | if(!compiled) { 133 | expect(meta["DependencyDisplayComponent"].View.length).to.eql(1); 134 | expect(meta["DependencyDisplayComponent"].View[0].encapsulation).to.be(undefined); 135 | expect(meta["HelloWorld"].View.length).to.eql(1); 136 | expect(meta["HelloWorld"].View[0].encapsulation).not.to.be(null); 137 | expect(meta["HelloWorld"].View[0].encapsulation).to.be.a('string'); 138 | expect(meta["HelloWorld"].View[0].encapsulation).to.eql("NONE"); 139 | } else { 140 | expect(alreadyConstructed["DependencyDisplayComponent"]).to.be.a('boolean'); 141 | expect(alreadyConstructed["DependencyDisplayComponent"]).to.eql(true); 142 | expect(alreadyConstructed["HelloWorld"]).to.be.a('boolean'); 143 | expect(alreadyConstructed["HelloWorld"]).to.eql(true); 144 | } 145 | 146 | expect(anno["DependencyDisplayComponent"].length).to.eql(2); 147 | expect(anno["DependencyDisplayComponent"][1].encapsulation).not.to.be(null); 148 | expect(anno["DependencyDisplayComponent"][1].encapsulation).to.be.a('number'); 149 | expect(anno["DependencyDisplayComponent"][1].encapsulation).to.be(browser.window.ng.ViewEncapsulation.NONE); 150 | expect(anno["HelloWorld"].length).to.eql(2); 151 | expect(anno["HelloWorld"][1].encapsulation).not.to.be(null); 152 | expect(anno["HelloWorld"][1].encapsulation).to.be.a('number'); 153 | expect(anno["HelloWorld"][1].encapsulation).to.eql(browser.window.ng.ViewEncapsulation.NONE); 154 | }); 155 | 156 | // Styles conversion. 157 | it('styles'); 158 | 159 | // StyleUrls conversion. 160 | it('styleUrls'); 161 | }); 162 | }; -------------------------------------------------------------------------------- /spec/runTests.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | /* 17 | > IO.JS version 3.0.0 18 | Basic webserver to serve files during tests 19 | Reference: http://stackoverflow.com/questions/6084360/using-node-js-as-a-simple-web-server 20 | 21 | > Run with: 22 | mocha runTests.js -t 5000 23 | 24 | > Requires: 25 | - connect 26 | - serve-static 27 | - zombie@4.0.13 28 | - mocha 29 | - expect.js 30 | */ 31 | "use strict" 32 | const zombie = require('zombie'); 33 | const expect = require('expect.js'); 34 | const connect = require('connect'); 35 | const serveStatic = require('serve-static'); 36 | const port = 8080; 37 | const specs = ['CompiledComponents.test.js', 'DirectiveMetadata.spec.js', 'ComponentMetadata.spec.js', 'ViewMetadata.spec.js']; 38 | 39 | // Launch webserver. Will be shut down automatically 40 | // once mocha has finished. 41 | connect().use(serveStatic(__dirname + "/../bin/")).listen(port); 42 | 43 | // As of Angular 2.0.0-alpha.35, the following message is displayed: 44 | // TypeError: Array.prototype.slice called on null or undefined 45 | // This is due to ZombieJS not refreshing its own DOM structure. Once 46 | // Angular compiles its' children, it expects that they should be present 47 | // in the DOM, however, as ZombieJS doesn't refresh the DOM, they 48 | // don't exist. 49 | zombie.silent = true; 50 | zombie.localhost('localhost', port); 51 | 52 | // Run spec tests. 53 | for(var spec of specs) { 54 | // Test compiled and non-compiled. 55 | for(var b of [false, true]) { 56 | const browser = new zombie({ 57 | waitFor: 2000, 58 | loadCSS: false, 59 | runScripts: true 60 | }); 61 | 62 | require('./' + spec).spec(browser, expect, b); 63 | } 64 | } -------------------------------------------------------------------------------- /src/BuildRegistry.hx: -------------------------------------------------------------------------------- 1 | package; 2 | 3 | import test.ChildComponent; 4 | import test.Dependency; 5 | import test.DependencyDisplayComponent; 6 | import test.FriendsService; 7 | import test.HelloWorld; 8 | import test.InputDirective; 9 | import test.ParentComponent; 10 | import test.TodoList; 11 | 12 | import testcompile.ChildComponent; 13 | import testcompile.Dependency; 14 | import testcompile.DependencyDisplayComponent; 15 | import testcompile.DisplayComponent; 16 | import testcompile.FriendsService; 17 | import testcompile.HelloWorld; 18 | import testcompile.InputDirective; 19 | import testcompile.ParentComponent; 20 | import testcompile.TodoList; 21 | import testcompile.MyDirective; 22 | import testcompile.NgModelDirective; 23 | import testcompile.NeedsGreeter; 24 | import testcompile.Greeter; 25 | 26 | /** 27 | * Dummy build registry to demonstrate 28 | * compile-time builds. It's main use is 29 | * to be a hub for all imports which will be 30 | * resolved as part of the build process. 31 | */ 32 | class BuildRegistry 33 | { 34 | private function new() 35 | { 36 | 37 | } 38 | } -------------------------------------------------------------------------------- /src/Main.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package; 17 | 18 | import angular2haxe.ng.Angular; 19 | import angular2haxe.Application; 20 | 21 | import test.ChildComponent; 22 | import test.Dependency; 23 | import test.DependencyDisplayComponent; 24 | import test.DisplayComponent; 25 | import test.ParentComponent; 26 | import test.TodoList; 27 | import test.HelloWorld; 28 | import test.InputDirective; 29 | 30 | @:build(angular2haxe.buildplugin.BuildPlugin.app([ 31 | testcompile.DisplayComponent, 32 | testcompile.TodoList, 33 | testcompile.ParentComponent, 34 | testcompile.ChildComponent, 35 | testcompile.MyDirective, 36 | testcompile.NgModelDirective, 37 | testcompile.Dependency, 38 | testcompile.DependencyDisplayComponent, 39 | testcompile.Greeter, 40 | testcompile.NeedsGreeter, 41 | testcompile.HelloWorld, 42 | testcompile.InputDirective 43 | ])) 44 | class Main 45 | { 46 | static function main() 47 | { 48 | // Create a new application, bootstrapping the 49 | // listed classes in the process. 50 | new Application([ 51 | 52 | test.DisplayComponent, 53 | test.TodoList, 54 | test.ParentComponent, 55 | test.ChildComponent, 56 | 57 | // --- Dependency.hx --- 58 | test.MyDirective, 59 | test.NgModelDirective, 60 | test.Dependency, 61 | 62 | // --- DependencyDisplayComponent.hx -- 63 | test.DependencyDisplayComponent, 64 | 65 | // --- HelloWorld.hx --- 66 | test.Greeter, 67 | test.NeedsGreeter, 68 | test.HelloWorld, 69 | 70 | test.InputDirective 71 | 72 | ]); 73 | } 74 | } -------------------------------------------------------------------------------- /src/angular2haxe/AngularExtension.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe; 17 | 18 | import angular2haxe.ng.NgFor; 19 | import angular2haxe.ng.NgIf; 20 | 21 | class AngularExtension 22 | { 23 | private static var angularClasses : Map> = [ 24 | "NgFor" => NgFor, 25 | "NgIf" => NgIf 26 | ]; 27 | 28 | private function new() { } 29 | 30 | public static function getAngularClasses() : Map> 31 | { 32 | return angularClasses; 33 | } 34 | 35 | public static function getAngularClass(name : String) : Class 36 | { 37 | if (angularClasses.exists(name)) 38 | { 39 | return angularClasses[name]; 40 | } 41 | 42 | return null; 43 | } 44 | 45 | public static function isAngularClass(name : String) : Bool 46 | { 47 | if (name.substr(0, 3) == "ng." || name.substr(0, 8) == "angular.") 48 | { 49 | name = getFullyQualifiedName(name); 50 | } 51 | 52 | return angularClasses.exists(name); 53 | } 54 | 55 | public static function getBareName(name : String) : String 56 | { 57 | if (name.substr(0, 3) == "ng.") 58 | { 59 | return name; 60 | } 61 | else if (name.substr(0, 8) == "angular.") 62 | { 63 | return name.substr(8); 64 | } 65 | 66 | return name; 67 | } 68 | 69 | public static function getFullyQualifiedName(name : String) : String 70 | { 71 | if (isAngularClass(name)) 72 | { 73 | return name; 74 | } 75 | 76 | return "ng." + getBareName(name); 77 | } 78 | } -------------------------------------------------------------------------------- /src/angular2haxe/Annotation.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe; 17 | 18 | class Annotation 19 | { 20 | private function new(data : Dynamic) { } 21 | } -------------------------------------------------------------------------------- /src/angular2haxe/AnnotationExtension.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe; 17 | 18 | import angular2haxe.buildplugin.BuildPlugin; 19 | import angular2haxe.ng.ComponentMetadata; 20 | import angular2haxe.ng.DirectiveMetadata; 21 | import angular2haxe.ng.ViewMetadata; 22 | 23 | // Type.resolveClass in macro works if type is imported 24 | //import test.HelloWorld; 25 | 26 | class AnnotationExtension 27 | { 28 | private function new() { } 29 | 30 | // Intended to be overridden in child class 31 | public static function transform(input : Dynamic, annotations : Array, parameters : Array) : Dynamic 32 | { 33 | return input; 34 | } 35 | 36 | /** 37 | * Resolve Haxe metadata input to the form Angular 38 | * expects, checking that the fields are of the 39 | * correct type. 40 | */ 41 | public static function resolveInputAnnotation(input : Dynamic, outputType : Class) : T 42 | { 43 | var output : T; 44 | 45 | output = Type.createInstance(outputType, []); 46 | 47 | for (field in Reflect.fields(input)) 48 | { 49 | if (Reflect.hasField(output, field)) 50 | { 51 | var inputField = Reflect.field(input, field); 52 | var outputClass = Type.getClass(Reflect.field(output, field)); 53 | 54 | // If outputClass is null, the output class is most likely Dynamic 55 | if (Std.is(inputField, outputClass) || outputClass == null) 56 | { 57 | var result = null; 58 | #if !macro 59 | // Deep copy array objects, so original meta is 60 | // preserved. 61 | // Reference: https://gist.github.com/Asmageddon/4013485 62 | if (Std.is(inputField, Array)) 63 | { 64 | result = Type.createInstance(outputClass, []); 65 | 66 | untyped 67 | { 68 | for (i in 0...inputField.length) 69 | { 70 | result.push(inputField[i]); 71 | } 72 | } 73 | } 74 | else 75 | { 76 | result = inputField; 77 | } 78 | #else 79 | result = inputField; 80 | #end 81 | 82 | Reflect.setField(output, field, result); 83 | } 84 | else 85 | { 86 | var inputClassName : String = Type.getClassName(Type.getClass(inputField)); 87 | var outputClassName : String = Type.getClassName(outputClass); 88 | Trace.error('Input type of field "${field}" (${inputClassName}) does not match type of output field (${outputClassName}).'); 89 | } 90 | } 91 | else 92 | { 93 | Trace.error('${Type.getClassName(outputType)} does not have field "${field}" and as such this field will be ignored.'); 94 | } 95 | } 96 | 97 | return output; 98 | } 99 | 100 | /** 101 | * Parse annotation injectors to be used in the Angular, resolving 102 | * strings to their respective class/type. 103 | * service parameters. 104 | * @param injector Annotation injector variable (i.e. hostInjector). 105 | * @return 106 | */ 107 | private static function parseServiceParameters(injector : Array) : Array 108 | { 109 | var serviceParams : Array = []; 110 | var index : Int = 0; 111 | 112 | for (app in injector) 113 | { 114 | if (app != null && app.length > 0) 115 | { 116 | var cl = Type.resolveClass(app); 117 | serviceParams.push(cl); 118 | injector[index] = cl; 119 | } 120 | 121 | index++; 122 | } 123 | return serviceParams; 124 | } 125 | 126 | /** 127 | * Parses an annotation injector variable. Most of the work in this instance is 128 | * deferred to AnnotationExtension.parseServiceParameters. 129 | * @param parameters Static variable of the same name located in an Angular class. 130 | * @param injector The injector variable to parse. 131 | */ 132 | private static function parseInjector(parameters : Array, injector : Array) 133 | { 134 | var serviceParameter : Array = parseServiceParameters(injector); 135 | 136 | if (serviceParameter != null && serviceParameter.length > 0) 137 | { 138 | parameters.push(serviceParameter); 139 | } 140 | } 141 | 142 | /** 143 | * Transform lifecycle variable names (String) to Angular 144 | * lifecycle variables (JS Object). 145 | * @param lifecycle 146 | */ 147 | private static function transformLifecycle(lifecycle : Array) 148 | { 149 | // Transform lifecycle values 150 | var index : Int = 0; 151 | 152 | while (index < lifecycle.length) 153 | { 154 | lifecycle[index] = LifecycleEventExtension.toAngular(cast(lifecycle[index], String)); 155 | index++; 156 | } 157 | } 158 | } -------------------------------------------------------------------------------- /src/angular2haxe/AnnotationPair.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe; 17 | 18 | typedef AnnotationPair = { 19 | annotation : Class, 20 | extension : Class 21 | }; -------------------------------------------------------------------------------- /src/angular2haxe/Application.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe; 17 | 18 | import haxe.rtti.Meta; 19 | import angular2haxe.ng.Angular; 20 | import angular2haxe.ng.ComponentMetadata; 21 | import angular2haxe.ng.DirectiveMetadata; 22 | import angular2haxe.ng.ViewMetadata; 23 | 24 | #if !macro 25 | import js.Lib; 26 | #end 27 | 28 | class Application 29 | { 30 | public function new(components : Array>) 31 | { 32 | // Patch for Angular 2 issue #3890: 33 | // https://github.com/angular/angular/issues/3890 34 | // angular2haxe issue #6: 35 | // https://github.com/nweedon/angular2haxe/issues/6 36 | untyped window.assert = function() { return true; }; 37 | 38 | // Bootstrap all components 39 | bootstrap(components); 40 | } 41 | 42 | /** 43 | * Bootstrap the application, which currently sets up component 44 | * classes and their respective annotations ready for Angular 2. 45 | * Once this is complete, angular.bootstrap is called for each 46 | * component supplied. 47 | * @param components - An array of valid component classes 48 | */ 49 | private function bootstrap(components : Array>) 50 | { 51 | var showDataInTrace : Bool = false; 52 | var validAnnotations : Map = [ 53 | "Component" => { annotation: ComponentMetadata, extension: ComponentAnnotationExtension }, 54 | "Directive" => { annotation: DirectiveMetadata, extension: DirectiveAnnotationExtension }, 55 | "View" => { annotation: ViewMetadata, extension: ViewAnnotationExtension }, 56 | ]; 57 | 58 | for (component in components) 59 | { 60 | var anno = Meta.getType(component); 61 | var className = Type.getClassName(component); 62 | var hasComponentAnnotation = false; 63 | 64 | if (Reflect.fields(component).indexOf('__alreadyConstructed') > -1) 65 | { 66 | // Parse Angular Object in annotations field. This has to be done 67 | // at runtime as all Angular Objects are external and do not resolve 68 | // at compile-time. 69 | var annotations : Array = Reflect.field(component, "annotations"); 70 | 71 | if (annotations != null) 72 | { 73 | // Annotations are built in the order: 74 | // Component, View, Directive (see BuildPlugin.hx) 75 | var metaNames : Array = ["Component", "View", "Directive"]; 76 | var index : Int = 0; 77 | 78 | for (data in annotations) 79 | { 80 | if (data != null) 81 | { 82 | // Set hasComponentAnnotation to true to 83 | // trigger Angular bootstrap process. 84 | if (index == 0) 85 | { 86 | hasComponentAnnotation = true; 87 | } 88 | 89 | // Call Annotation extension function to 90 | // transform all string representations 91 | // to Angular Object data 92 | Reflect.callMethod( validAnnotations[metaNames[index]].extension, 93 | Reflect.field(validAnnotations[metaNames[index]].extension, "postCompileTransform"), 94 | [data]); 95 | } 96 | 97 | index++; 98 | } 99 | 100 | index = 0; 101 | 102 | // Filter out all null entries. 103 | for (index in 0...annotations.length) 104 | { 105 | if (annotations[index] == null) 106 | { 107 | annotations.remove(null); 108 | } 109 | } 110 | } 111 | } 112 | else 113 | { 114 | // Create 'annotations' and 'parameters' fields, so they don't have 115 | // to be added by a developer every time a new class is created. 116 | Reflect.setField(component, "annotations", []); 117 | Reflect.setField(component, "parameters", []); 118 | 119 | // Get the annotation and parameters fields from the component class. 120 | var annotations : Array = Reflect.field(component, "annotations"); 121 | var parameters : Array = Reflect.field(component, "parameters"); 122 | 123 | // Only bootstrap once. 124 | if (annotations != null && annotations.length == 0) 125 | { 126 | Trace.log('=> Bootstrapping ${className}'); 127 | 128 | for(name in Reflect.fields(anno)) 129 | { 130 | if (validAnnotations.exists(name)) 131 | { 132 | var field = Reflect.field(anno, name); 133 | 134 | // Call AnnotationExtension transform function. This transform 135 | // function takes Haxe metadata input and transforms it into the 136 | // data that Angular 2 expects. 137 | // For example, Haxe metadata only handles constants (no class names), 138 | // so the string representations of the class names must be transformed into 139 | // JavaScript classes/functions at runtime. 140 | var input = field[0]; 141 | 142 | var result = Reflect.callMethod(validAnnotations[name].extension, 143 | Reflect.field(validAnnotations[name].extension, "transform"), 144 | [input, annotations, parameters]); 145 | 146 | annotations.push(Type.createInstance(validAnnotations[name].annotation, [result])); 147 | } 148 | else 149 | { 150 | Trace.error(name + " is not a valid annotation."); 151 | } 152 | } 153 | 154 | hasComponentAnnotation = Reflect.fields(anno).indexOf("Component") >= 0; 155 | 156 | if (showDataInTrace) 157 | { 158 | Trace.log('Annotations:\n${annotations}'); 159 | Trace.log('Parameters:\n${parameters}'); 160 | } 161 | } 162 | else 163 | { 164 | Trace.error('${className} does not have an "annotations" static variable in its class definition!'); 165 | } 166 | } 167 | 168 | // Add event listener for Angular Bootstrap 169 | #if !macro 170 | js.Browser.document.addEventListener("DOMContentLoaded", function() 171 | { 172 | if (hasComponentAnnotation) 173 | { 174 | Angular.bootstrap(component); 175 | Reflect.setField(component, "__bootstrapped", true); 176 | } 177 | 178 | Trace.log('=> Finished bootstrapping ${className}'); 179 | }); 180 | #end 181 | } 182 | } 183 | } -------------------------------------------------------------------------------- /src/angular2haxe/ComponentAnnotationExtension.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe; 17 | 18 | import angular2haxe.ng.ComponentConstructorData; 19 | import angular2haxe.ng.LifecycleEvent; 20 | 21 | class ComponentAnnotationExtension extends AnnotationExtension 22 | { 23 | public function new() 24 | { 25 | super(); 26 | } 27 | 28 | /** 29 | * Transforms Haxe metadata input into valid Angular 2 annotation data. 30 | * @param input - Haxe metadata 31 | * @param annotations - annotations static field present in angular component 32 | * @param parameters - parameters static field present in angular component 33 | * @return Angular 2 component annotation constructor 34 | */ 35 | @:keep 36 | public static function transform(input : Dynamic, annotations : Array, parameters : Array) : ComponentConstructorData 37 | { 38 | var output : ComponentConstructorData = AnnotationExtension.resolveInputAnnotation(input, ComponentConstructorData); 39 | 40 | // Transform appInjector to resolve to the 41 | // correct JavaScript classes. 42 | if (parameters != null && output.viewBindings != null) 43 | { 44 | AnnotationExtension.parseInjector(parameters, output.viewBindings); 45 | } 46 | 47 | if (parameters != null && output.bindings != null) 48 | { 49 | AnnotationExtension.parseInjector(parameters, output.bindings); 50 | } 51 | 52 | if (output.lifecycle != null) 53 | { 54 | AnnotationExtension.transformLifecycle(output.lifecycle); 55 | } 56 | 57 | return output; 58 | } 59 | 60 | @:keep 61 | public static function postCompileTransform(data : ComponentConstructorData) 62 | { 63 | if (data != null) 64 | { 65 | var bindings : Array> = [data.viewBindings, data.bindings]; 66 | 67 | for (binding in bindings) 68 | { 69 | if (binding != null) 70 | { 71 | var index : Int = 0; 72 | 73 | for (element in binding) 74 | { 75 | if (Std.is(element, String)) 76 | { 77 | binding[index] = AngularExtension.getAngularClass(element); 78 | } 79 | 80 | index++; 81 | } 82 | } 83 | } 84 | } 85 | 86 | if (data.lifecycle != null) 87 | { 88 | AnnotationExtension.transformLifecycle(data.lifecycle); 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /src/angular2haxe/DirectiveAnnotationExtension.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe; 17 | 18 | import angular2haxe.ng.DirectiveConstructorData; 19 | import haxe.ds.StringMap; 20 | import haxe.Json; 21 | import haxe.macro.Expr; 22 | 23 | class DirectiveAnnotationExtension extends AnnotationExtension 24 | { 25 | public function new() 26 | { 27 | super(); 28 | } 29 | 30 | /** 31 | * Transforms Haxe metadata input into valid Angular 2 annotation data. 32 | * @param input - Haxe metadata 33 | * @param annotations - annotations static field present in angular component 34 | * @param parameters - parameters static field present in angular component 35 | * @return Angular 2 directive annotation constructor 36 | */ 37 | @:keep 38 | public static function transform(input : Dynamic, annotations : Array, parameters : Array) : DirectiveConstructorData 39 | { 40 | #if !macro 41 | // Update host events. Metadata objects with a string as their 42 | // key have '@$__hx__' prefixed to them, so it needs to be removed. 43 | if (input.host != null) 44 | { 45 | var outputHost : Dynamic = { }; 46 | // Iterate through input.host and strip prefixed 47 | // tag from all variables that have it. 48 | for (field in Reflect.fields(input.host)) 49 | { 50 | var index : Int = field.indexOf("@$__hx__"); 51 | 52 | if (index > -1) 53 | { 54 | // Remove the prepended @$__hx__ and add 55 | // it to the new object. 56 | var key = field.substring(8); 57 | Reflect.setField(outputHost, key, Reflect.field(input.host, field)); 58 | } 59 | } 60 | 61 | input.host = outputHost; 62 | } 63 | #end 64 | 65 | // Resolve final input. 66 | var output : DirectiveConstructorData = AnnotationExtension.resolveInputAnnotation(input, DirectiveConstructorData); 67 | 68 | if (parameters != null && output.bindings != null) 69 | { 70 | AnnotationExtension.parseInjector(parameters, output.bindings); 71 | } 72 | 73 | if (output.lifecycle != null) 74 | { 75 | AnnotationExtension.transformLifecycle(output.lifecycle); 76 | } 77 | 78 | return output; 79 | } 80 | 81 | @:keep 82 | public static function postCompileTransform(data : DirectiveConstructorData) 83 | { 84 | if (data != null) 85 | { 86 | if (data.bindings != null) 87 | { 88 | var index : Int = 0; 89 | 90 | for (element in data.bindings) 91 | { 92 | if (Std.is(element, String)) 93 | { 94 | data.bindings[index] = AngularExtension.getAngularClass(element); 95 | } 96 | 97 | index++; 98 | } 99 | } 100 | 101 | if (data.lifecycle != null) 102 | { 103 | AnnotationExtension.transformLifecycle(data.lifecycle); 104 | } 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /src/angular2haxe/KeyboardEvent.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe; 17 | 18 | #if !macro 19 | import js.html.KeyboardEventInit; 20 | 21 | class KeyboardEvent extends js.html.KeyboardEvent 22 | { 23 | @:native("target") 24 | public var _target : Dynamic; 25 | 26 | public function new(typeArg:String, ?keyboardEventInitDict:KeyboardEventInit) 27 | { 28 | super(typeArg, keyboardEventInitDict); 29 | } 30 | } 31 | #else 32 | class KeyboardEvent 33 | { 34 | 35 | } 36 | #end 37 | -------------------------------------------------------------------------------- /src/angular2haxe/LifecycleEventExtension.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe; 17 | 18 | import angular2haxe.ng.LifecycleEvent; 19 | 20 | #if macro 21 | import haxe.macro.Context; 22 | #end 23 | 24 | class LifecycleEventExtension 25 | { 26 | private static var supportedLifecycleEvents : Map; 27 | private static var initialised : Bool = false; 28 | 29 | private function new() { } 30 | 31 | private static function init() 32 | { 33 | if (!initialised) 34 | { 35 | supportedLifecycleEvents = [ 36 | "onChange" => LifecycleEvent.onChange, 37 | "onInit" => LifecycleEvent.onInit, 38 | "onCheck" => LifecycleEvent.onCheck, 39 | "onAllChangesDone" => LifecycleEvent.onAllChangesDone, 40 | "onDestroy" => LifecycleEvent.onDestroy 41 | ]; 42 | 43 | initialised = true; 44 | } 45 | } 46 | 47 | /** 48 | * Convert string to an Angular Lifecycle object. If the 49 | * object does not exist, null is returned. 50 | * @param lifecycleEvent String representing an Angular Lifecycle event (i.e. onInit). 51 | * @return 52 | */ 53 | public static function toAngular(lifecycleEvent : String) : Dynamic 54 | { 55 | #if !macro 56 | init(); 57 | 58 | if (supportedLifecycleEvents.exists(lifecycleEvent)) 59 | { 60 | return supportedLifecycleEvents[lifecycleEvent]; 61 | } 62 | else 63 | { 64 | Trace.error('Angular does not have LifecycleEvent "${lifecycleEvent}"'); 65 | return lifecycleEvent; 66 | } 67 | #else 68 | return lifecycleEvent; 69 | #end 70 | } 71 | } -------------------------------------------------------------------------------- /src/angular2haxe/Trace.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe; 17 | 18 | #if macro 19 | import haxe.macro.Context; 20 | #end 21 | 22 | /** 23 | * Debug Level: 24 | * 25 | * ALL: Show all log messages (trace, warning, error) 26 | * WARN: Show warning and error messages 27 | * ERROR: Show just error messages 28 | */ 29 | class Trace 30 | { 31 | #if (debug_level=="WARN") 32 | private static var logLevel : String = "WARN"; 33 | #elseif (debug_level == "ERROR") 34 | private static var logLevel : String = "ERROR"; 35 | #else 36 | private static var logLevel : String = "ALL"; 37 | #end 38 | 39 | private function new() 40 | { 41 | } 42 | 43 | /** 44 | * Feed string to console.error 45 | * @param info String to display as an error. 46 | */ 47 | public static inline function error(info : String) 48 | { 49 | #if macro 50 | Context.error(info, Context.currentPos()); 51 | #else 52 | untyped 53 | { 54 | console.error(info); 55 | } 56 | #end 57 | } 58 | 59 | public static inline function warning(info : String) 60 | { 61 | #if macro 62 | Context.warning(info, Context.currentPos()); 63 | #else 64 | if (logLevel == "WARN" || logLevel == "ALL") 65 | { 66 | untyped 67 | { 68 | console.warn(info); 69 | } 70 | } 71 | #end 72 | } 73 | 74 | /** 75 | * Feed string to console.log 76 | * @param info String to display as a log message. 77 | */ 78 | public static inline function log(info : String) 79 | { 80 | if (logLevel == "ALL") 81 | { 82 | trace(info); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /src/angular2haxe/ViewAnnotationExtension.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe; 17 | 18 | import angular2haxe.ng.ViewConstructorData; 19 | import angular2haxe.AngularExtension; 20 | import angular2haxe.ng.ViewEncapsulation; 21 | 22 | #if macro 23 | import angular2haxe.buildplugin.BuildPlugin; 24 | #end 25 | 26 | class ViewAnnotationExtension extends AnnotationExtension 27 | { 28 | private function new() 29 | { 30 | super(); 31 | } 32 | 33 | /** 34 | * Transforms Haxe metadata input into valid Angular 2 annotation data. 35 | * @param input - Haxe metadata 36 | * @param annotations - annotations static field present in angular component 37 | * @param parameters - parameters static field present in angular component 38 | * @return Angular 2 view annotation constructor 39 | */ 40 | @:keep 41 | public static function transform(input : Dynamic, annotations : Array, parameters : Array) : ViewConstructorData 42 | { 43 | var output : ViewConstructorData = AnnotationExtension.resolveInputAnnotation(input, ViewConstructorData); 44 | var index : Int = 0; 45 | 46 | #if !macro 47 | output.encapsulation = ViewEncapsulationExtension.toAngular(output.encapsulation); 48 | #end 49 | 50 | // Transform directive names was field[0] 51 | if (output.directives != null) 52 | { 53 | for (directive in output.directives) 54 | { 55 | if (directive != null && directive.length > 0) 56 | { 57 | // Possible issue using eval here? The field has to exist using 58 | // valid field characters, so is there even a possibility that a 59 | // vulnerability exists? 60 | directive = StringTools.htmlEscape(directive); 61 | 62 | // extern classes won't resolve 63 | #if macro 64 | var resolvedClass; 65 | // Can't resolve angular classes at build-time (as they 66 | // are extenal), so they have to be converted at run-time. 67 | if (!AngularExtension.isAngularClass(directive)) 68 | { 69 | resolvedClass = BuildPlugin.resolveClass(directive); 70 | } 71 | else 72 | { 73 | // Angular classes have to be resolved at run-time 74 | // due to them being external to the build. 75 | resolvedClass = directive; 76 | } 77 | #else 78 | var resolvedClass = Type.resolveClass(directive); 79 | #end 80 | 81 | if (resolvedClass != null) 82 | { 83 | output.directives[index] = resolvedClass; 84 | } 85 | else 86 | { 87 | var angularClass = AngularExtension.getAngularClass(directive); 88 | 89 | if (angularClass != null) 90 | { 91 | output.directives[index] = angularClass; 92 | } 93 | else 94 | { 95 | Trace.error('The definition for ${directive} does not exist!'); 96 | } 97 | } 98 | } 99 | 100 | index++; 101 | } 102 | } 103 | 104 | return output; 105 | } 106 | 107 | @:keep 108 | public static function postCompileTransform(data : ViewConstructorData) 109 | { 110 | if (data != null) 111 | { 112 | if (data.directives != null) 113 | { 114 | var index : Int = 0; 115 | 116 | for (element in data.directives) 117 | { 118 | if (Std.is(element, String)) 119 | { 120 | data.directives[index] = AngularExtension.getAngularClass(element); 121 | } 122 | 123 | index++; 124 | } 125 | } 126 | 127 | data.encapsulation = ViewEncapsulationExtension.toAngular(data.encapsulation); 128 | } 129 | } 130 | } -------------------------------------------------------------------------------- /src/angular2haxe/ViewEncapsulationExtension.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe; 17 | import angular2haxe.ng.ViewEncapsulation; 18 | 19 | class ViewEncapsulationExtension 20 | { 21 | private function new() 22 | { 23 | 24 | } 25 | 26 | public static function toAngular(name : String) : Int 27 | { 28 | return switch(name) { 29 | case "EMULATED" : ViewEncapsulation.EMULATED; 30 | case "NATIVE" : ViewEncapsulation.NATIVE; 31 | case "NONE" : ViewEncapsulation.NONE; 32 | default : ViewEncapsulation.NONE; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/angular2haxe/buildplugin/BuildPlugin.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe.buildplugin; 17 | 18 | #if macro 19 | import haxe.macro.Compiler; 20 | import haxe.macro.Context; 21 | import haxe.macro.Expr; 22 | import haxe.macro.ExprTools; 23 | import haxe.macro.Type in MType; 24 | import haxe.macro.Type.ClassType; 25 | import haxe.macro.MacroStringTools; 26 | #end 27 | 28 | import angular2haxe.Application; 29 | import angular2haxe.Trace; 30 | import angular2haxe.AngularExtension; 31 | 32 | // Command line: -D using_registry 33 | #if using_registry 34 | /* Import a build registry. The registry 35 | * holds all imports that need to be resolved 36 | * at build-time. 37 | * If you don't have one, follow the link for a 38 | * reference implementation: 39 | * 40 | * https://github.com/nweedon/Angular2-Haxe/blob/master/src/BuildRegistry.hx 41 | */ 42 | import BuildRegistry; 43 | #end 44 | /* --- */ 45 | 46 | class BuildPlugin 47 | { 48 | private function new() 49 | { 50 | 51 | } 52 | 53 | #if macro 54 | private static var QUOTED_FIELD_PREFIX = "@$__hx__"; 55 | 56 | /** 57 | * Resolve class by name at build time. Classes will resolve if 58 | * they are imported explicitly in this file. 59 | * @param name Fully-qualified name of the class to resolve (including package names). 60 | * @return Class representation of the name provided. If the class doesn't resolve, an error is thrown. 61 | */ 62 | public static function resolveClass(name : String) : Class 63 | { 64 | var cl : Class; 65 | 66 | if (AngularExtension.isAngularClass(name)) 67 | { 68 | name = AngularExtension.getFullyQualifiedName(name); 69 | } 70 | 71 | cl = Type.resolveClass(name); 72 | 73 | if (cl == null) 74 | { 75 | // Skip compiling Angular classes. 76 | if (!AngularExtension.isAngularClass(name)) 77 | { 78 | Trace.error('${name} has not resolved to a class. Make sure it is imported in the BuildPlugin file.'); 79 | } 80 | } 81 | 82 | return cl; 83 | } 84 | 85 | /** 86 | * Extract value from expression. Credit to nadako: 87 | * https://gist.github.com/nadako/9081608 88 | * @param e 89 | * @return 90 | */ 91 | private static function extractValue(e : Expr) : Dynamic 92 | { 93 | switch (e.expr) 94 | { 95 | case EConst(c): 96 | switch (c) 97 | { 98 | case CInt(s): 99 | var i = Std.parseInt(s); 100 | return (i != null) ? i : Std.parseFloat(s); // if the number exceeds standard int return as float 101 | case CFloat(s): 102 | return Std.parseFloat(s); 103 | case CString(s): 104 | return s; 105 | case CIdent("null"): 106 | return null; 107 | case CIdent("true"): 108 | return true; 109 | case CIdent("false"): 110 | return false; 111 | case CIdent(s): 112 | return s; 113 | default: 114 | } 115 | case EBlock([]): 116 | return {}; 117 | case EObjectDecl(fields): 118 | var object = {}; 119 | for (field in fields) 120 | Reflect.setField(object, unquoteField(field.field), extractValue(field.expr)); 121 | return object; 122 | case EArrayDecl(exprs): 123 | return [for (e in exprs) extractValue(e)]; 124 | case EField(e, f): 125 | var pack = extractValue(e); 126 | return '${pack}.${f}'; 127 | default: 128 | } 129 | throw new Error("Invalid JSON expression", e.pos); 130 | } 131 | 132 | /** 133 | * Strips "@$__hx__" from all object declarations. 134 | * see https://github.com/HaxeFoundation/haxe/issues/2642 135 | * @param name 136 | * @return 137 | */ 138 | private static function unquoteField(name:String):String 139 | { 140 | return (name.indexOf(QUOTED_FIELD_PREFIX) == 0) ? name.substr(QUOTED_FIELD_PREFIX.length) : name; 141 | } 142 | 143 | /** 144 | * Compile the modules in modulesExpr by adding 145 | * '@:build' metadata to them, which in turn triggers 146 | * BuildPlugin.build(). This function also updates the 147 | * main method so that the components are bootstrapped 148 | * at run-time. 149 | * @param modulesExpr 150 | * @return 151 | */ 152 | macro public static function app(modulesExpr : Expr) : Array 153 | { 154 | var modules : Array = extractValue(modulesExpr); 155 | var moduleClasses : Array> = []; 156 | var originalBlock : Array; 157 | var fields : Array = Context.getBuildFields(); 158 | var mainFieldName : String = "main"; 159 | var blockModified : Bool = false; 160 | 161 | for (module in modules) 162 | { 163 | Trace.log('Adding build metadata for ${module}'); 164 | Compiler.addMetadata("@:build(angular2haxe.buildplugin.BuildPlugin.build())", module); 165 | Compiler.addMetadata("@:keep", module); 166 | moduleClasses.push(resolveClass(module)); 167 | } 168 | 169 | var mainExists : Bool = Lambda.exists(fields, function(field : Field) : Bool 170 | { 171 | return field.name == mainFieldName; 172 | }); 173 | 174 | if (mainExists) 175 | { 176 | // Remove the main function, it will be replaced with a new one. 177 | for (i in 0...fields.length) 178 | { 179 | if (fields[i].name == mainFieldName) 180 | { 181 | // Retrieve main function. 182 | var func : haxe.macro.Expr.Function = switch(fields[i].kind) 183 | { 184 | case FFun(f): f; 185 | default: null; 186 | }; 187 | 188 | // Retrieve original code block. If an original 189 | // doesn't exist, create an empty block. 190 | originalBlock = switch(func.expr.expr) 191 | { 192 | case EBlock(b): b; 193 | default: []; 194 | } 195 | 196 | // If we don't have an empty block, search through it 197 | // for an application statement and update the array of 198 | // components to be bootstrapped. 199 | if (originalBlock.length > 0) 200 | { 201 | for (expr in originalBlock) 202 | { 203 | // Only search for ENew expressions, as an application is created 204 | // as such: 205 | // new angular2haxe.Application([ ... ]); 206 | // Retrieve the type and params used in the ENew expression. 207 | var appInitParams = switch(expr.expr) 208 | { 209 | case ENew(tp, params): { type: tp, params: params }; 210 | default: null; 211 | } 212 | 213 | if (appInitParams != null) 214 | { 215 | // Search for ENew({ name => Application, pack => [], params => [] }, ... ) 216 | // or pack == [angular2haxe] 217 | if (appInitParams.type.name == "Application" && (appInitParams.type.pack.length == 0 || appInitParams.type.pack == ["angular2haxe"])) 218 | { 219 | // Strip out the EArrayDecl values so the resulting 220 | // array can be added to. 221 | var arrayDecl = switch(appInitParams.params[0].expr) 222 | { 223 | case EArrayDecl(v): v; 224 | default: null; 225 | } 226 | 227 | if (arrayDecl != null) 228 | { 229 | // Add module classes to current declaration. As arrayDecl 230 | // etc. are references and not values, there is no need to 231 | // reconstruct the block. 232 | for (cl in moduleClasses) 233 | { 234 | arrayDecl.push(Context.makeExpr(cl, Context.currentPos())); 235 | } 236 | 237 | blockModified = true; 238 | } 239 | } 240 | } 241 | } 242 | } 243 | 244 | // If the original block was not modified, update the 245 | // current block which creates a new application. 246 | if (!blockModified) 247 | { 248 | // Remove original code block. 249 | fields.splice(i, 1); 250 | 251 | // Add the new main function, with the new call to 252 | // bootstrap all provided modules / classes. 253 | fields.push({ 254 | name: mainFieldName, 255 | doc: null, 256 | meta: [], 257 | access: [AStatic, APublic], 258 | kind: FieldType.FFun({ 259 | ret: macro : Void, 260 | params: [], 261 | expr: macro { 262 | $b{originalBlock}; 263 | new angular2haxe.Application($v{moduleClasses}); 264 | }, 265 | args: [] 266 | }), 267 | pos: Context.currentPos() 268 | }); 269 | } 270 | } 271 | } 272 | } 273 | 274 | return fields; 275 | } 276 | 277 | /** 278 | * Compile data at build-time rather than run-time. 279 | * @return 280 | */ 281 | macro public static function build() : Array 282 | { 283 | var attachedClass : ClassType = Context.getLocalClass().get(); 284 | var attachedMetadata : Metadata = attachedClass.meta.get(); 285 | var fields : Array = Context.getBuildFields(); 286 | 287 | // Exit if already built. 288 | for (i in 0...fields.length) 289 | { 290 | if (fields[i].name == '__alreadyConstructed') 291 | { 292 | return null; 293 | } 294 | } 295 | 296 | // Use template strings to build final output code / macro 297 | var validAnnotations : Map> = [ 298 | "Component" => ComponentAnnotationExtension, 299 | "Directive" => DirectiveAnnotationExtension, 300 | "View" => ViewAnnotationExtension 301 | ]; 302 | 303 | // Set default values for annotations and parameters fields. 304 | var annotationData : Array = []; 305 | var annotationKeys : Array = []; 306 | var parameters : Array = []; 307 | 308 | Trace.log('=> Started compiling "${attachedClass.name}"'); 309 | 310 | for (meta in attachedMetadata) 311 | { 312 | if (["Component", "Directive", "View"].indexOf(meta.name) > -1) 313 | { 314 | var data : Dynamic = { }; 315 | var annotationName : String = meta.name; 316 | 317 | Trace.log('\t-> Parsing ${meta.name} annotation'); 318 | 319 | for (param in meta.params) 320 | { 321 | var params : Array = param.expr.getParameters()[0]; 322 | var i : Int = 0; 323 | 324 | // Cast all annotation values at build-time into values 325 | // we can work with. 326 | for (paramNames in params) 327 | { 328 | var e : Expr = params[i].expr; 329 | var fieldValue : Dynamic; 330 | 331 | // Extract value from expression. 332 | fieldValue = extractValue(e); 333 | 334 | Reflect.setField(data, paramNames.field, fieldValue); 335 | i++; 336 | } 337 | } 338 | 339 | Reflect.callMethod(validAnnotations[annotationName], 340 | Reflect.field(validAnnotations[annotationName], "transform"), 341 | [data, annotationData, parameters]); 342 | 343 | annotationData.push(data); 344 | annotationKeys.push(annotationName); 345 | // Clear annotation as it is not needed. 346 | attachedClass.meta.remove(annotationName); 347 | } 348 | } 349 | 350 | var keepMeta : MetadataEntry = { 351 | pos: Context.currentPos(), 352 | params: [], 353 | name: ':keep' 354 | }; 355 | 356 | // Create annotations and parameters fields 357 | fields.push({ 358 | name: 'annotations', 359 | doc: null, 360 | meta: [keepMeta], 361 | access: [AStatic, APublic], 362 | kind: FVar(macro : Array, macro [ 363 | untyped __js__("{1} ? new ng.ComponentMetadata({0}) : null", $v{ annotationData[annotationKeys.indexOf("Component")] }, $v{ annotationKeys.indexOf("Component") > -1 }), 364 | untyped __js__("{1} ? new ng.ViewMetadata({0}) : null", $v{ annotationData[annotationKeys.indexOf("View")] }, $v{ annotationKeys.indexOf("View") > -1 } ), 365 | untyped __js__("{1} ? new ng.DirectiveMetadata({0}) : null", $v{ annotationData[annotationKeys.indexOf("Directive")] }, $v{ annotationKeys.indexOf("Directive") > -1 }), 366 | ]), 367 | pos: Context.currentPos() 368 | }); 369 | 370 | fields.push({ 371 | name: 'parameters', 372 | doc: null, 373 | meta: [keepMeta], 374 | access: [AStatic, APublic], 375 | kind: FVar(macro : Array, Context.makeExpr(parameters, Context.currentPos())), 376 | pos: Context.currentPos() 377 | }); 378 | 379 | // Create field to note that the class has been 380 | // constructed at build-time. 381 | fields.push({ 382 | name: '__alreadyConstructed', 383 | doc: null, 384 | meta: [keepMeta], 385 | access: [AStatic, APublic], 386 | kind: FVar(macro : Bool, macro true), 387 | pos: Context.currentPos() 388 | }); 389 | 390 | Trace.log('=> Finished compiling "${attachedClass.name}"'); 391 | return fields; 392 | } 393 | #end 394 | } -------------------------------------------------------------------------------- /src/angular2haxe/ng/Angular.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe.ng; 17 | 18 | /** 19 | * Haxe representation of Angular 2.0 20 | */ 21 | @:native('ng') 22 | extern class Angular 23 | { 24 | function new(); 25 | 26 | static function bootstrap(cl : Class) : Angular; 27 | } -------------------------------------------------------------------------------- /src/angular2haxe/ng/ComponentConstructorData.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe.ng; 17 | 18 | /** 19 | * Reference: 20 | * https://github.com/angular/angular/blob/master/modules/angular2/src/core/annotations_impl/annotations.ts 21 | * 22 | * Notes: 23 | * - 'exportAs' is included in the constructor, but according to the source (25 July 2015), 24 | * doesn't do anything yet. 25 | */ 26 | @:keep 27 | class ComponentConstructorData 28 | { 29 | public var selector : String = null; 30 | public var properties : Array = []; 31 | public var events : Array = []; 32 | public var host : Map = new Map(); 33 | public var lifecycle : Array = []; 34 | public var bindings : Array = []; 35 | public var exportAs : String = null; 36 | public var compileChildren : Bool = true; 37 | public var viewBindings : Array = []; 38 | public var changeDetection : String = "DEFAULT"; 39 | 40 | public function new() 41 | { 42 | } 43 | } -------------------------------------------------------------------------------- /src/angular2haxe/ng/ComponentMetadata.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe.ng; 17 | 18 | import angular2haxe.ng.ComponentConstructorData; 19 | import angular2haxe.Annotation; 20 | 21 | @:native('ng.ComponentMetadata') 22 | extern class ComponentMetadata extends Annotation 23 | { 24 | function new(data : ComponentConstructorData); 25 | } -------------------------------------------------------------------------------- /src/angular2haxe/ng/DirectiveConstructorData.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe.ng; 17 | import haxe.ds.StringMap; 18 | 19 | /** 20 | * Reference: 21 | * https://angular.io/docs/js/latest/api/annotations/DirectiveAnnotation-class.html 22 | * https://github.com/angular/angular/blob/master/modules/angular2/src/core/annotations_impl/annotations.ts 23 | */ 24 | @:keep 25 | class DirectiveConstructorData 26 | { 27 | public var selector : String = null; 28 | public var properties : Array = []; 29 | public var events : Array = []; 30 | public var host : Dynamic = null; 31 | public var lifecycle : Array = []; 32 | public var bindings : Array = []; 33 | public var exportAs : String = null; 34 | public var compileChildren : Bool = true; 35 | 36 | public function new() 37 | { 38 | } 39 | } -------------------------------------------------------------------------------- /src/angular2haxe/ng/DirectiveMetadata.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe.ng; 17 | import angular2haxe.Annotation; 18 | 19 | @:native('ng.DirectiveMetadata') 20 | extern class DirectiveMetadata extends Annotation 21 | { 22 | function new(data : DirectiveConstructorData); 23 | } -------------------------------------------------------------------------------- /src/angular2haxe/ng/EventEmitter.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe.ng; 17 | 18 | @:native('angular.EventEmitter') 19 | extern class EventEmitter 20 | { 21 | function new(); 22 | public function next(event : Dynamic) : EventEmitter; 23 | } -------------------------------------------------------------------------------- /src/angular2haxe/ng/LifecycleEvent.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe.ng; 17 | 18 | @:native('ng.LifecycleEvent') 19 | extern class LifecycleEvent 20 | { 21 | @:native('onChange') 22 | public static var onChange : Dynamic; 23 | 24 | @:native('onInit') 25 | public static var onInit : Dynamic; 26 | 27 | @:native('onCheck') 28 | public static var onCheck : Dynamic; 29 | 30 | @:native('onAllChangesDone') 31 | public static var onAllChangesDone : Dynamic; 32 | 33 | @:native('onDestroy') 34 | public static var onDestroy : Dynamic; 35 | 36 | private function new() { } 37 | } -------------------------------------------------------------------------------- /src/angular2haxe/ng/NgFor.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe.ng; 17 | 18 | @:native('ng.NgFor') 19 | extern class NgFor 20 | { 21 | // TODO: Original Constructor 22 | // viewContainer: ViewContainerRef, templateRef: TemplateRef, pipes: Pipes, cdr: ChangeDetectorRef 23 | public function new(viewContainer : Dynamic, templateRef : Dynamic, pipes : Dynamic, cdr : Dynamic) 24 | { 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /src/angular2haxe/ng/NgIf.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe.ng; 17 | 18 | @:native('ng.NgIf') 19 | extern class NgIf 20 | { 21 | // TODO: Original Constructor 22 | // viewContainer: ViewContainerRef, templateRef: TemplateRef 23 | public function new(viewContainer : Dynamic, templateRef : Dynamic) 24 | { 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /src/angular2haxe/ng/ViewConstructorData.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe.ng; 17 | 18 | /** 19 | * Reference: 20 | * https://angular.io/docs/js/latest/api/annotations/ViewAnnotation-class.html 21 | */ 22 | @:keep 23 | class ViewConstructorData 24 | { 25 | public var templateUrl : String = null; 26 | public var template : String = null; 27 | public var directives : Array = []; 28 | public var encapsulation : Dynamic = null; 29 | public var styles : Array = []; 30 | public var styleUrls : Array = []; 31 | 32 | public function new() 33 | { 34 | } 35 | } -------------------------------------------------------------------------------- /src/angular2haxe/ng/ViewEncapsulation.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe.ng; 17 | 18 | @:native('ng.ViewEncapsulation') 19 | extern class ViewEncapsulation 20 | { 21 | @:native('EMULATED') 22 | public static var EMULATED : Int; 23 | @:native('NATIVE') 24 | public static var NATIVE : Int; 25 | @:native('NONE') 26 | public static var NONE : Int; 27 | 28 | private function new() { } 29 | } -------------------------------------------------------------------------------- /src/angular2haxe/ng/ViewMetadata.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package angular2haxe.ng; 17 | import angular2haxe.Annotation; 18 | import angular2haxe.ng.ViewConstructorData; 19 | 20 | @:native('ng.ViewMetadata') 21 | extern class ViewMetadata extends Annotation 22 | { 23 | function new(data : ViewConstructorData); 24 | } -------------------------------------------------------------------------------- /src/test/ChildComponent.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package test; 17 | 18 | import angular2haxe.ng.Angular; 19 | 20 | /* 21 | * Reference: 22 | * https://angular.io/docs/js/latest/guide/making-components.html 23 | */ 24 | 25 | @Component({ 26 | selector: 'child' 27 | }) 28 | @View({ 29 | template: '

{{ message }}

' 30 | }) 31 | @:expose 32 | @:keep 33 | class ChildComponent 34 | { 35 | private var message = "I am the child."; 36 | 37 | public function new() 38 | { 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/Dependency.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package test; 17 | 18 | import angular2haxe.ng.Angular; 19 | import angular2haxe.ng.EventEmitter; 20 | import angular2haxe.Trace; 21 | 22 | /* 23 | * Reference: 24 | * https://angular.io/docs/js/latest/api/annotations/DirectiveAnnotation-class.html 25 | * http://victorsavkin.com/post/119943127151/angular-2-template-syntax 26 | * 27 | * Note: Events on Dependency and NgModelDirective classes are work-in-progress. 28 | */ 29 | 30 | @Directive({ 31 | selector: '[dependency]', 32 | properties: [ 33 | "id: dependency" 34 | ], 35 | lifecycle: ["onInit"] 36 | }) 37 | @:expose 38 | @:keep 39 | class Dependency 40 | { 41 | public var id : String; 42 | 43 | public function new() 44 | { 45 | } 46 | 47 | public function onInit() 48 | { 49 | Trace.log('Dependency.hx result:\n${this}'); 50 | } 51 | 52 | public function onMouseEnter(event : Dynamic) 53 | { 54 | trace('onMouseEnter: ${id}'); 55 | } 56 | 57 | public function onMouseLeave() 58 | { 59 | trace('onMouseLeave: ${id}'); 60 | } 61 | 62 | public function onResize(event : Dynamic) 63 | { 64 | trace('resize ${event}'); 65 | } 66 | } 67 | 68 | /** 69 | * Injecting dependency with hostInjector 70 | */ 71 | @Directive({ 72 | selector: '[my-directive]', 73 | lifecycle: ["onInit"], 74 | bindings: ["test.Dependency"] 75 | }) 76 | @:expose 77 | @:keep 78 | class MyDirective 79 | { 80 | private var dependency : Dependency; 81 | 82 | public function new(?dependency : Dependency) 83 | { 84 | if (dependency != null) 85 | { 86 | this.dependency = dependency; 87 | } 88 | } 89 | 90 | public function onInit() 91 | { 92 | Trace.log('MyDirective Dependency:\n${dependency}'); 93 | } 94 | } 95 | 96 | @Directive({ 97 | selector: '[ng-model]', 98 | properties: ['ngModel'] 99 | }) 100 | @:expose 101 | @:keep 102 | class NgModelDirective 103 | { 104 | private var ngModel : String = ""; 105 | private var ngModelChanged : EventEmitter = new EventEmitter(); 106 | 107 | public function new() 108 | { 109 | } 110 | 111 | public function modelChanged(event : Dynamic) 112 | { 113 | Trace.log(event); 114 | ngModelChanged.next(event.target.value); 115 | } 116 | } -------------------------------------------------------------------------------- /src/test/DependencyDisplayComponent.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package test; 17 | 18 | import angular2haxe.ng.Angular; 19 | import angular2haxe.ng.LifecycleEvent; 20 | import test.Dependency.MyDirective; 21 | 22 | /* 23 | * Reference: 24 | * https://angular.io/docs/js/latest/guide/displaying-data.html 25 | */ 26 | 27 | @Component({ 28 | selector: 'dependency-display', 29 | compileChildren: true 30 | }) 31 | @View({ 32 | directives: ["test.Dependency", "test.MyDirective", "test.NgModelDirective"], 33 | templateUrl: "templates/dependency.tpl.html" 34 | }) 35 | @:expose 36 | @:keep 37 | class DependencyDisplayComponent 38 | { 39 | public function new() 40 | { 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/DisplayComponent.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package test; 17 | 18 | import angular2haxe.ng.Angular; 19 | 20 | /* 21 | * Reference: 22 | * https://angular.io/docs/js/latest/guide/displaying-data.html 23 | */ 24 | 25 | @Component({ 26 | selector: 'display', 27 | viewBindings: ["test.FriendsService"] 28 | }) 29 | @View({ 30 | directives: ["NgFor", "NgIf"], 31 | template: '

My name: {{ myName }}

Friends:

  • {{ name }}

You have many friends!

' 32 | }) 33 | @:keep 34 | @:expose 35 | class DisplayComponent 36 | { 37 | private var myName : String; 38 | private var names : Array; 39 | 40 | public function new(?friends : FriendsService) 41 | { 42 | myName = "Alice"; 43 | 44 | if (friends != null) 45 | { 46 | names = friends.names; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/FriendsService.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package test; 17 | 18 | @:expose 19 | class FriendsService 20 | { 21 | public var names : Array; 22 | 23 | @:keep 24 | public function new() 25 | { 26 | names = ["Aarav", "Martín", "Shannon", "Ariana", "Kai"]; 27 | } 28 | } -------------------------------------------------------------------------------- /src/test/HelloWorld.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package test; 17 | 18 | import angular2haxe.buildplugin.BuildPlugin; 19 | 20 | /** 21 | * Reference(s): 22 | * https://angular.io/docs/js/latest/api/annotations/DirectiveAnnotation-class.html 23 | * 24 | * Uses: 25 | * Directive => hostInjector 26 | * Component => hostInjector 27 | */ 28 | 29 | @:expose 30 | @:keep 31 | class Greeter 32 | { 33 | public function new() { } 34 | public function greet(name : String) 35 | { 36 | return 'Hello ${name}!'; 37 | } 38 | } 39 | 40 | @Directive({ 41 | selector: 'needs-greeter', 42 | bindings: [ 43 | "test.Greeter" 44 | ] 45 | }) 46 | @:expose 47 | @:keep 48 | class NeedsGreeter 49 | { 50 | private var greeter : Greeter; 51 | 52 | public function new(greeter : Greeter) 53 | { 54 | this.greeter = greeter; 55 | } 56 | } 57 | 58 | @Component({ 59 | selector: 'greet', 60 | viewBindings: [ 61 | "test.Greeter" 62 | ], 63 | exportAs: 'componentGreet' 64 | }) 65 | @View({ 66 | template: "{{ greeter.greet('World') }}", 67 | directives: ["test.NeedsGreeter"], 68 | encapsulation: "NONE" 69 | }) 70 | @:expose 71 | @:keep 72 | class HelloWorld 73 | { 74 | private var greeter : Greeter; 75 | 76 | public function new(greeter : Greeter) 77 | { 78 | this.greeter = greeter; 79 | } 80 | } -------------------------------------------------------------------------------- /src/test/InputDirective.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package test; 17 | import angular2haxe.KeyboardEvent; 18 | 19 | @Directive({ 20 | selector: 'input', 21 | lifecycle: ["onInit", "onChange", "onAllChangesDone", "onCheck"], 22 | host: { 23 | '(keyup)' : 'onKeyUp($event)' 24 | }, 25 | exportAs: 'input-directive' 26 | }) 27 | @:expose 28 | @:keep 29 | class InputDirective 30 | { 31 | public function new() 32 | { 33 | 34 | } 35 | 36 | #if !macro 37 | public function onInit() 38 | { 39 | trace('InputDirective.onInit: ${this}'); 40 | } 41 | 42 | public function onChange() 43 | { 44 | 45 | } 46 | 47 | public function onAllChangesDone() 48 | { 49 | 50 | } 51 | 52 | public function onCheck() 53 | { 54 | 55 | } 56 | 57 | public function onKeyUp(event : KeyboardEvent) 58 | { 59 | trace('You just pressed a key with key code: ${event.keyCode}!'); 60 | } 61 | #end 62 | } -------------------------------------------------------------------------------- /src/test/ParentComponent.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package test; 17 | 18 | import angular2haxe.ng.Angular; 19 | 20 | /* 21 | * Reference: 22 | * https://angular.io/docs/js/latest/guide/making-components.html 23 | */ 24 | 25 | @Component({ 26 | selector: 'parent' 27 | }) 28 | @View({ 29 | directives: ["test.ChildComponent"], 30 | template: '

{{ message }}

' 31 | }) 32 | @:keep 33 | class ParentComponent 34 | { 35 | private var message = "I am the parent."; 36 | 37 | public function new() 38 | { 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/TodoList.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package test; 17 | 18 | import angular2haxe.KeyboardEvent; 19 | import angular2haxe.Trace; 20 | import test.InputDirective; 21 | 22 | /* 23 | * Reference: 24 | * https://angular.io/docs/js/latest/guide/user-input.html 25 | */ 26 | 27 | @Component({ 28 | selector: 'todo-list', 29 | properties: ["lastValue", "todos"], 30 | lifecycle: ["onInit", "onChange", "onAllChangesDone", "onCheck"], 31 | changeDetection: "CHECK_ALWAYS" 32 | }) 33 | @View({ 34 | directives: ["NgFor", "NgIf", "test.InputDirective"], 35 | template: 'Last value: {{lastValue}}
  • {{ todo }}
', 36 | }) 37 | @:expose 38 | @:keep 39 | class TodoList 40 | { 41 | private var todos : Array; 42 | public var lastValue : String = ""; 43 | 44 | public function new() 45 | { 46 | todos = ["Eat Breakfast", "Walk Dog", "Breathe"]; 47 | lastValue = todos[todos.length - 1]; 48 | } 49 | #if !macro 50 | public function doneTyping(event : KeyboardEvent) 51 | { 52 | if (event.which == 13) 53 | { 54 | addTodo(event._target.value); 55 | event._target.value = ""; 56 | } 57 | } 58 | #end 59 | public function addTodo(todo : String) 60 | { 61 | lastValue = todo; 62 | todos.push(todo); 63 | } 64 | 65 | public function onInit() 66 | { 67 | Trace.log('Lifecycle onInit:\n${this}'); 68 | } 69 | 70 | public function onCheck() 71 | { 72 | Trace.log('Lifecycle onCheck'); 73 | } 74 | 75 | public function onChange(changes : Dynamic) 76 | { 77 | Trace.log('Lifecycle onChange: ${changes}'); 78 | } 79 | 80 | public function onAllChangesDone() 81 | { 82 | Trace.log('Lifecycle onAllChangesDone'); 83 | } 84 | } -------------------------------------------------------------------------------- /src/testcompile/ChildComponent.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package testcompile; 17 | 18 | import angular2haxe.ng.Angular; 19 | 20 | /* 21 | * Reference: 22 | * https://angular.io/docs/js/latest/guide/making-components.html 23 | */ 24 | 25 | @Component({ 26 | selector: 'c-child' 27 | }) 28 | @View({ 29 | template: '

{{ message }}

' 30 | }) 31 | @:expose 32 | class ChildComponent 33 | { 34 | private var message = "I am the child."; 35 | 36 | public function new() 37 | { 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/testcompile/Dependency.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package testcompile; 17 | 18 | import angular2haxe.ng.Angular; 19 | import angular2haxe.ng.EventEmitter; 20 | import angular2haxe.Trace; 21 | 22 | /* 23 | * Reference: 24 | * https://angular.io/docs/js/latest/api/annotations/DirectiveAnnotation-class.html 25 | * http://victorsavkin.com/post/119943127151/angular-2-template-syntax 26 | * 27 | * Note: Events on Dependency and NgModelDirective classes are work-in-progress. 28 | */ 29 | 30 | @Directive({ 31 | selector: '[c-dependency]', 32 | properties: [ 33 | "id: c-dependency" 34 | ], 35 | lifecycle: ["onInit"] 36 | }) 37 | @:expose 38 | class Dependency 39 | { 40 | public var id : String; 41 | 42 | public function new() 43 | { 44 | } 45 | 46 | public function onInit() 47 | { 48 | Trace.log('Dependency.hx result:\n${this}'); 49 | } 50 | 51 | public function onMouseEnter(event : Dynamic) 52 | { 53 | trace('onMouseEnter: ${id}'); 54 | } 55 | 56 | public function onMouseLeave() 57 | { 58 | trace('onMouseLeave: ${id}'); 59 | } 60 | 61 | public function onResize(event : Dynamic) 62 | { 63 | trace('resize ${event}'); 64 | } 65 | } -------------------------------------------------------------------------------- /src/testcompile/DependencyDisplayComponent.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package testcompile; 17 | 18 | import angular2haxe.ng.Angular; 19 | import angular2haxe.ng.LifecycleEvent; 20 | import test.Dependency.MyDirective; 21 | 22 | /* 23 | * Reference: 24 | * https://angular.io/docs/js/latest/guide/displaying-data.html 25 | */ 26 | 27 | @Component({ 28 | selector: 'c-dependency-display', 29 | compileChildren: true 30 | }) 31 | @View({ 32 | directives: ["testcompile.Dependency", "testcompile.MyDirective", "testcompile.NgModelDirective"], 33 | templateUrl: "templates/dependency.tpl.html" 34 | }) 35 | @:expose 36 | class DependencyDisplayComponent 37 | { 38 | public function new() 39 | { 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/testcompile/DisplayComponent.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package testcompile; 17 | 18 | import angular2haxe.ng.Angular; 19 | 20 | /* 21 | * Reference: 22 | * https://angular.io/docs/js/latest/guide/displaying-data.html 23 | */ 24 | 25 | @Component({ 26 | selector: 'c-display', 27 | viewBindings: ["testcompile.FriendsService"] 28 | }) 29 | @View({ 30 | directives: ["NgFor", "NgIf"], 31 | template: '

My name: {{ myName }}

Friends:

  • {{ name }}

You have many friends!

' 32 | }) 33 | @:expose 34 | class DisplayComponent 35 | { 36 | private var myName : String; 37 | private var names : Array; 38 | 39 | public function new(?friends : FriendsService) 40 | { 41 | myName = "Alice"; 42 | 43 | if (friends != null) 44 | { 45 | names = friends.names; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/testcompile/FriendsService.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package testcompile; 17 | 18 | @:expose 19 | class FriendsService 20 | { 21 | public var names : Array; 22 | 23 | @:keep 24 | public function new() 25 | { 26 | names = ["Aarav", "Martín", "Shannon", "Ariana", "Kai"]; 27 | } 28 | } -------------------------------------------------------------------------------- /src/testcompile/Greeter.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package testcompile; 17 | 18 | @:expose 19 | class Greeter 20 | { 21 | public function new() { } 22 | public function greet(name : String) 23 | { 24 | return 'Hello ${name}!'; 25 | } 26 | } -------------------------------------------------------------------------------- /src/testcompile/HelloWorld.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package testcompile; 17 | 18 | import angular2haxe.buildplugin.BuildPlugin; 19 | 20 | /** 21 | * Reference(s): 22 | * https://angular.io/docs/js/latest/api/annotations/DirectiveAnnotation-class.html 23 | * 24 | * Uses: 25 | * Directive => hostInjector 26 | * Component => hostInjector 27 | */ 28 | 29 | @Component({ 30 | selector: 'c-greet', 31 | viewBindings: [ 32 | "testcompile.Greeter" 33 | ], 34 | exportAs: 'componentGreet' 35 | }) 36 | @View({ 37 | template: "{{ greeter.greet('World') }}", 38 | directives: ["testcompile.NeedsGreeter"], 39 | encapsulation: "NONE" 40 | }) 41 | @:expose 42 | class HelloWorld 43 | { 44 | private var greeter : Greeter; 45 | 46 | public function new(greeter : Greeter) 47 | { 48 | this.greeter = greeter; 49 | } 50 | } -------------------------------------------------------------------------------- /src/testcompile/InputDirective.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package testcompile; 17 | 18 | import angular2haxe.KeyboardEvent; 19 | 20 | @Directive({ 21 | selector: 'input', 22 | lifecycle: ["onInit", "onChange", "onAllChangesDone", "onCheck"], 23 | host: { 24 | '(keyup)' : 'onKeyUp($event)' 25 | }, 26 | exportAs: 'input-directive' 27 | }) 28 | @:expose 29 | class InputDirective 30 | { 31 | public function new() 32 | { 33 | 34 | } 35 | 36 | #if !macro 37 | public function onInit() 38 | { 39 | trace('InputDirective.onInit: ${this}'); 40 | } 41 | 42 | public function onChange() 43 | { 44 | 45 | } 46 | 47 | public function onAllChangesDone() 48 | { 49 | 50 | } 51 | 52 | public function onCheck() 53 | { 54 | 55 | } 56 | 57 | public function onKeyUp(event : KeyboardEvent) 58 | { 59 | trace('You just pressed a key with key code: ${event.keyCode}!'); 60 | } 61 | #end 62 | } -------------------------------------------------------------------------------- /src/testcompile/MyDirective.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package testcompile; 17 | 18 | import angular2haxe.Trace; 19 | 20 | @Directive({ 21 | selector: '[my-directive]', 22 | lifecycle: ["onInit"], 23 | bindings: ["testcompile.Dependency"] 24 | }) 25 | @:expose 26 | class MyDirective 27 | { 28 | private var dependency : Dependency; 29 | 30 | public function new(?dependency : Dependency) 31 | { 32 | if (dependency != null) 33 | { 34 | this.dependency = dependency; 35 | } 36 | } 37 | 38 | public function onInit() 39 | { 40 | Trace.log('MyDirective Dependency:\n${dependency}'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/testcompile/NeedsGreeter.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package testcompile; 17 | 18 | @Directive({ 19 | selector: 'c-needs-greeter', 20 | bindings: [ 21 | "testcompile.Greeter" 22 | ] 23 | }) 24 | @:expose 25 | class NeedsGreeter 26 | { 27 | private var greeter : Greeter; 28 | 29 | public function new(greeter : Greeter) 30 | { 31 | this.greeter = greeter; 32 | } 33 | } -------------------------------------------------------------------------------- /src/testcompile/NgModelDirective.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package testcompile; 17 | 18 | import angular2haxe.ng.EventEmitter; 19 | import angular2haxe.Trace; 20 | 21 | @Directive({ 22 | selector: '[ng-model]', 23 | properties: ['ngModel'] 24 | }) 25 | @:expose 26 | class NgModelDirective 27 | { 28 | private var ngModel : String = ""; 29 | private var ngModelChanged : EventEmitter = new EventEmitter(); 30 | 31 | public function new() 32 | { 33 | } 34 | 35 | public function modelChanged(event : Dynamic) 36 | { 37 | Trace.log(event); 38 | ngModelChanged.next(event.target.value); 39 | } 40 | } -------------------------------------------------------------------------------- /src/testcompile/ParentComponent.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package testcompile; 17 | 18 | import angular2haxe.ng.Angular; 19 | 20 | /* 21 | * Reference: 22 | * https://angular.io/docs/js/latest/guide/making-components.html 23 | */ 24 | 25 | @Component({ 26 | selector: 'c-parent' 27 | }) 28 | @View({ 29 | directives: ["testcompile.ChildComponent"], 30 | template: '

{{ message }}

' 31 | }) 32 | class ParentComponent 33 | { 34 | private var message = "I am the parent."; 35 | 36 | public function new() 37 | { 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/testcompile/TodoList.hx: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Niall Frederick Weedon 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package testcompile; 17 | 18 | import angular2haxe.KeyboardEvent; 19 | import angular2haxe.Trace; 20 | import test.InputDirective; 21 | 22 | /* 23 | * Reference: 24 | * https://angular.io/docs/js/latest/guide/user-input.html 25 | */ 26 | 27 | @Component({ 28 | selector: 'c-todo-list', 29 | properties: ["lastValue", "todos"], 30 | lifecycle: ["onInit", "onChange", "onAllChangesDone", "onCheck"], 31 | changeDetection: "CHECK_ALWAYS" 32 | }) 33 | @View({ 34 | directives: ["NgFor", "NgIf", "testcompile.InputDirective"], 35 | template: 'Last value: {{lastValue}}
  • {{ todo }}
', 36 | }) 37 | @:expose 38 | class TodoList 39 | { 40 | private var todos : Array; 41 | public var lastValue : String = ""; 42 | 43 | public function new() 44 | { 45 | todos = ["Eat Breakfast", "Walk Dog", "Breathe"]; 46 | lastValue = todos[todos.length - 1]; 47 | } 48 | 49 | #if !macro 50 | public function doneTyping(event : KeyboardEvent) 51 | { 52 | if (event.which == 13) 53 | { 54 | addTodo(event._target.value); 55 | event._target.value = ""; 56 | } 57 | } 58 | #end 59 | 60 | public function addTodo(todo : String) 61 | { 62 | lastValue = todo; 63 | todos.push(todo); 64 | } 65 | 66 | public function onInit() 67 | { 68 | Trace.log('Lifecycle onInit:\n${this}'); 69 | } 70 | 71 | public function onCheck() 72 | { 73 | Trace.log('Lifecycle onCheck'); 74 | } 75 | 76 | public function onChange(changes : Dynamic) 77 | { 78 | Trace.log('Lifecycle onChange: ${changes}'); 79 | } 80 | 81 | public function onAllChangesDone() 82 | { 83 | Trace.log('Lifecycle onAllChangesDone'); 84 | } 85 | } --------------------------------------------------------------------------------