.gitignore000066400000000000000000000003251516112644000130460ustar00rootroot00000000000000/node_modules /build /dist .idea/workspace.xml .idea/tasks.xml .idea/profiles_settings.xml .idea/inspectionProfiles/Project_Default.xml .idea/inspectionProfiles/profiles_settings.xml node_modules/.yarn-integrity .idea/000077500000000000000000000000001516112644000120365ustar00rootroot00000000000000.idea/angular-compile.iml000066400000000000000000000005201516112644000156150ustar00rootroot00000000000000 .idea/codeStyleSettings.xml000066400000000000000000000004251516112644000162350ustar00rootroot00000000000000 .idea/inspectionProfiles/000077500000000000000000000000001516112644000157155ustar00rootroot00000000000000.idea/inspectionProfiles/profiles_settings.xml000066400000000000000000000002341516112644000222010ustar00rootroot00000000000000 .idea/misc.xml000066400000000000000000000002561516112644000135160ustar00rootroot00000000000000 .idea/modules.xml000066400000000000000000000004321516112644000142270ustar00rootroot00000000000000 .idea/vcs.xml000066400000000000000000000002471516112644000133560ustar00rootroot00000000000000 .npmignore000066400000000000000000000003451516112644000130570ustar00rootroot00000000000000/.idea /artifacts /build /test /node_modules /*.iml /*.ipr /*.iws /.travis.yml /.scrutinizer.yml /Gruntfile.js /*.lock *.log /corifeus-boot.json # Corifeus / P3X /src /tsconfig* # need to allow ts for awesome=typscript-loader .scrutinizer.yml000066400000000000000000000007761516112644000142520ustar00rootroot00000000000000checks: javascript: true filter: excluded_paths: - node_modules/* build: cache: disabled: true dependencies: before: - export LATEST=$(nvm ls-remote | tail -1) - nvm install $LATEST # - nvm use $LATEST - npm install grunt-cli -g - npm install - node_modules/protractor/bin/webdriver-manager update tests: override: - command: 'grunt coverage' coverage: file: 'build/coverage/clover.xml' format: 'clover' .travis.yml000066400000000000000000000005751516112644000131760ustar00rootroot00000000000000sudo: required dist: trusty addons: apt: sources: - google-chrome packages: - google-chrome-stable language: node_js node_js: - "node" before_script: - "export DISPLAY=:99.0" - "sh -e /etc/init.d/xvfb start" - sleep 3 # give xvfb some time to start - npm install grunt-cli -g - npm install - node_modules/protractor/bin/webdriver-manager update Gruntfile.js000066400000000000000000000022761516112644000133620ustar00rootroot00000000000000module.exports = (grunt) => { //node node_modules/protractor/bin/webdriver-manager update const builder = require('corifeus-builder-angular'); /* webdriver-manager/selenium/update-config.json node_modules/protractor/bin/webdriver-manager update */ const loader = new builder.loader(grunt); loader.angular({ root: builder.config.folder.test.angularWebpack.root, replacer: { type: 'p3x', npmio: true, }, config: { clean: { 'cory-publish': [ 'dist' ] } } }); grunt.registerTask('run', builder.config.task.run.angular); grunt.registerTask('default', builder.config.task.build.angularAotJit); grunt.registerTask('aot', builder.config.task.build.angularAot); grunt.registerTask('aot-jit', builder.config.task.build.angularAotJit); grunt.registerTask('aot-test', ['webpack:cory-build-aot', 'cory-test-connect']); grunt.registerTask('coverage', 'karma:cory-angular'); grunt.registerTask('publish', ['cory-replace', 'cory-npm', 'cory-publish-angular']); //cori-test:angular-protractor // cori-test:angular-karma }LICENSE000066400000000000000000000021411516112644000120610ustar00rootroot00000000000000MIT License Copyright (c) 2017 Patrik Laszlo / patrikx3 / https://patrikx3.com and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. README.md000066400000000000000000000116711516112644000123430ustar00rootroot00000000000000[//]: #@corifeus-header [![Build Status](https://travis-ci.org/patrikx3/angular-compile.svg?branch=master)](https://travis-ci.org/patrikx3/angular-compile) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/patrikx3/angular-compile/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/patrikx3/angular-compile/?branch=master) [![Code Coverage](https://scrutinizer-ci.com/g/patrikx3/angular-compile/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/patrikx3/angular-compile/?branch=master) [![NPM](https://nodei.co/npm/p3x-angular-compile.png?downloads=true&downloadRank=true&stars=true)](https://www.npmjs.com/package/p3x-angular-compile/) --- # Angular Dynamic Compile service and directive This is an open source project. Just code. ### Node Version Requirement ``` >=7.8.0 ``` ### Built on Node ``` v8.6.0 ``` The ```async``` and ```await``` keywords are required. Install NodeJs: https://nodejs.org/en/download/package-manager/ # Description [//]: #@corifeus-header:end # Use case Dynamic compile components by a string template for Angular. You can provide a context, that you can use with anything (for clicking for free etc..) ## NPM & Version It is a ```CommonJS``` bundle. The version reflects the Angular version (```AngularMajor.AngularMinor.Build-Commit```). ## Install ```bash npm install --save p3x-angular-compile # or yarn add p3x-angular-compile ``` ## AOT + JIT It is not working out of the box (the default is either JIT or AOT, not both), but the apps become 10 folds faster. The ``@ngtools/webpack`` is AOT and the ```awesome-typescript-loader``` is JIT only. The solution can be architect with the ```@angular/compiler``` and the ```awesome-typescript-loader``` together. A miracle! Example here: [More info about AOT + JIT](https://pages.corifeus.com/github/corifeus-builder-angular/artifacts/readme/skeleton.html) ### Size If you want very small bundle, use ```gzip```. ## Usage ```typescript import { CompileModule} from "p3x-angular-compile" // the module settings @NgModule({ imports: [ // multiple directives in a shared module like this CorifeusWebMaterialModule, CompileModule.forRoot({ module: { schemas: [CUSTOM_ELEMENTS_SCHEMA], declarations: [MyDynamicElement ], // though you are better a shared component like imports: [ CorifeusWebMaterialModule ] } }) ], declarations: [ Page, ], providers: [ ], bootstrap: [ Page ] }) export class Module { }; ``` ```html
``` ```typescript // a page example export class Page { data: string = "
It is working
"; alert() { alert('ok'); } } ``` #### Actual used dynamic compiler I use a dynamic Markdown page with ```p3x-angular-compile```: [Module](https://github.com/patrikx3/corifeus-app-web-pages/blob/master/src/angular/module.ts) , [Example page](https://github.com/patrikx3/corifeus-app-web-pages/blob/master/src/angular/modules/cory-page.ts) #### Service [Please refer to use an a service](https://github.com/patrikx3/angular-compile/blob/master/test/angular-webpack/angular/page.ts) ### Options [Reference for the Angular module settings.]( https://github.com/angular/angular/blob/master/packages/core/src/metadata/ng_module.ts) The templates are cached. ```typescript export interface CompileOptions { // cached by template template: string; container: ViewContainerRef; context?: any, // you can customize here any you want to // CommonModule, BrowserModule are auto added // (like *ngIf and angular default directives) // though CompileModule.forRoot is usually enough // so you do not need to use it module?: NgModule; onCompiled?: Function, onError?: Function; } ``` ### Deployed example [Corifeus Pages (JIT + AOT at once)](https://pages.corifeus.com) [https://github.com/patrikx3/corifeus-app-web-pages/blob/master/src/angular/modules/cory-page.ts](https://github.com/patrikx3/corifeus-app-web-pages/blob/master/src/angular/modules/cory-page.ts) ## Dev environment end test ```bash npm install -g yarn git clone https://github.com/patrikx3/angular-compile.git cd angular-compile yarn install grunt run|default ``` [http://localhost:8080](http://localhost:8080) # Errors ## Type x is part of the declarations of 2 modules Basically, you need a shared component. https://stackoverflow.com/questions/42993580/angular-2-type-childcomponent-is-a-part-of-the-declarations-of-2-modules-par [//]: #@corifeus-footer --- [**P3X-ANGULAR-COMPILE**](https://pages.corifeus.com/angular-compile) Build v4.4.61-147 [Corifeus](http://www.corifeus.com) by [Patrik Laszlo](http://patrikx3.com) [//]: #@corifeus-footer:end angular-compile.iml000066400000000000000000000005171516112644000146430ustar00rootroot00000000000000 index.ts000066400000000000000000000000271516112644000125340ustar00rootroot00000000000000export * from "./src"; package.json000066400000000000000000000020561516112644000133470ustar00rootroot00000000000000{ "name": "p3x-angular-compile", "version": "4.4.81-165", "corifeus": { "prefix": "p3x-", "publish": true, "type": "p3x", "code": "Logico", "nodejs": "v8.6.0" }, "description": "Angular Dynamic Compile service and directive", "main": "dist/index.js", "typings": "dist/index", "scripts": { "test": "grunt" }, "repository": { "type": "git", "url": "git+https://github.com/patrikx3/angular-compile.git" }, "keywords": [ "p3x", "angular", "ng", "compile", "html", "angular", "dynamic", "aot" ], "author": "Patrik Laszlo ", "license": "MIT", "bugs": { "url": "https://github.com/patrikx3/angular-compile/issues" }, "homepage": "https://pages.corifeus.com/angular-compile", "devDependencies": { "corifeus-builder-angular": "^4.4.144-193", "corifeus-web": "^4.4.80-171", "corifeus-web-material": "^4.4.103-202" }, "dependencies": { "@types/lodash": "^4.14.77", "lodash": "^4.17.4" }, "engines": { "node": ">=7.8.0" } }src/000077500000000000000000000000001516112644000116455ustar00rootroot00000000000000src/CompileAttribute.ts000066400000000000000000000023751516112644000155000ustar00rootroot00000000000000import { Directive, Input, Injectable, ViewContainerRef, OnInit, OnChanges, SimpleChanges, Type, ModuleWithProviders, NgModule, } from '@angular/core'; import { CompileService } from './CompileService'; @Directive({ selector: '[p3x-compile]' }) @Injectable() export class CompileAttribute implements OnInit, OnChanges{ @Input('p3x-compile') html: string; @Input('p3x-compile-ctx') context: any; @Input('p3x-compile-module') module: NgModule; @Input('p3x-compile-imports') imports: Array | ModuleWithProviders | any[]>; async update() { if (this.html === undefined || this.html.trim() === '') { this.container.clear(); return; } await this.service.compile({ template: this.html, container: this.container, context: this.context, imports: this.imports, module: this.module }) } ngOnInit() { this.update(); } ngOnChanges(changes: SimpleChanges) { //fixme only update with the required changes this.update(); } constructor( private container: ViewContainerRef, private service: CompileService ) {} }src/CompileModule.ts000066400000000000000000000017651516112644000147640ustar00rootroot00000000000000 import { CompileService, CompileServiceConfig, } from "./CompileService"; import { CompileAttribute} from "./CompileAttribute"; import { NgModule, ModuleWithProviders } from '@angular/core'; import { Compiler } from '@angular/core'; import {JitCompilerFactory} from '@angular/compiler'; export function createJitCompiler () { return new JitCompilerFactory([{useDebug: false, useJit: true}]).createCompiler(); } // exports = component @NgModule({ imports: [ ], declarations: [ CompileAttribute, ], providers: [ CompileService, { provide: Compiler, useFactory: createJitCompiler}, ], exports: [ CompileAttribute, ], entryComponents: [ ] }) export class CompileModule { static forRoot(config: CompileServiceConfig) : ModuleWithProviders { return { ngModule: CompileModule, providers: [ {provide: CompileServiceConfig, useValue: config } ] }; } } src/CompileService.ts000066400000000000000000000067341516112644000151400ustar00rootroot00000000000000import { Component, NgModule, Injectable, Compiler, ViewContainerRef, ModuleWithProviders, Type, Optional } from '@angular/core'; import { CommonModule } from '@angular/common'; import { BrowserModule } from '@angular/platform-browser'; import { cloneDeep } from 'lodash'; export interface CompileOptions { template: string; container: ViewContainerRef; imports?: Array | ModuleWithProviders | any[]>; context?: any, onCompiled?: Function, onError?: Function; module?: NgModule; } const cache : any = {}; export class CompileServiceConfig { module: NgModule } let SingletonDefaultModule: NgModule; @Injectable() export class CompileService { constructor( private compiler: Compiler, @Optional() config: CompileServiceConfig, ) { if (config !== undefined && config !== null) { if (config.module !== undefined && config.module !== null) { SingletonDefaultModule = config.module; } } } public async compile(opts: CompileOptions) { try { const factory = await this.createFactory(opts); opts.container.clear(); const cmp : any = opts.container.createComponent(factory); cmp.instance.context = opts.context; } catch (e) { if (opts.onError) { opts.onError(e) } else { console.error(e); } } } private async createFactory(opts: CompileOptions) { const cacheKey = opts.template; if (Object.keys(cache).indexOf(cacheKey) > -1) { return cache[cacheKey]; } cache[cacheKey] = (async() => { try { @Component({ template: opts.template }) class TemplateComponent { context: any } let module : NgModule = {}; if (opts.module !== undefined) { module = cloneDeep(opts.module); } else if (SingletonDefaultModule !== undefined && SingletonDefaultModule !== null) { module = cloneDeep(SingletonDefaultModule); } module.imports = module.imports || []; module.imports.push( CommonModule ); module.imports.push( BrowserModule ); if (opts.imports !== undefined) { module.imports = module.imports.concat(opts.imports) } if (module.declarations === undefined) { module.declarations = [ TemplateComponent ]; } else { module.declarations.push(TemplateComponent); } @NgModule(module) class TemplateModule { } const component = await this.compiler.compileModuleAndAllComponentsAsync(TemplateModule); const factory = component.componentFactories.find((comp) => comp.componentType === TemplateComponent ); cache[cacheKey] = factory; if (opts.onCompiled) { opts.onCompiled(component); } return factory; } catch (e) { delete cache[cacheKey]; throw e; } })(); return cache[cacheKey]; } } src/index.ts000066400000000000000000000001471516112644000133260ustar00rootroot00000000000000export * from "./CompileService"; export * from "./CompileAttribute"; export * from "./CompileModule"; test/000077500000000000000000000000001516112644000120355ustar00rootroot00000000000000test/angular-karma/000077500000000000000000000000001516112644000145575ustar00rootroot00000000000000test/angular-karma/CompileHtmlService.ts000066400000000000000000000015601516112644000206670ustar00rootroot00000000000000// you need unlinked npm-s!!! import { TestBed } from '@angular/core/testing'; import { inject } from '@angular/core/testing'; import {CompileAttribute, CompileService } from '../../src' describe('CompileHtml', () => { let service: CompileService; beforeEach(() => { TestBed.configureTestingModule({ imports: [ ], declarations: [ CompileAttribute ], providers: [ CompileService ], }); }); beforeEach(inject([CompileService], (_service: CompileService) => { service = _service; })); it ('CompileService', (/*done*/) => { // expect(service instanceof CompileService).toBeTruthy(); /* setTimeout(()=> { console.log('done later'); done(); }, 1000); */ }); });test/angular-protractor/000077500000000000000000000000001516112644000156635ustar00rootroot00000000000000test/angular-protractor/test.js000066400000000000000000000015451516112644000172050ustar00rootroot00000000000000browser.ignoreSynchronization = true; describe('CompileHtml', () => { browser.get(`index.html`); const clicker = (button, counter) => { const total = 5; for(let i =0; i < total - 1; i++) { button.click(); browser.waitForAngular(); } const count = counter.getText(); expect(count).toEqual(total.toString()); } it('Service', (done) => { setTimeout(() => { const button = element(by.id('button-container')) const counter = element(by.id('counter-container')); clicker(button, counter); done(); }, 3000) }); it('Attribute', (done) => { const button = element(by.id('button-attribute')) const counter = element(by.id('counter-attribute')); clicker(button, counter); done(); }); });test/angular-webpack/000077500000000000000000000000001516112644000151005ustar00rootroot00000000000000test/angular-webpack/angular/000077500000000000000000000000001516112644000165315ustar00rootroot00000000000000test/angular-webpack/angular/bundle.aot.ts000066400000000000000000000005061516112644000211350ustar00rootroot00000000000000import { enableProdMode } from '@angular/core'; enableProdMode(); import 'corifeus-web/src/bundle'; import { platformBrowser } from '@angular/platform-browser'; import {ModuleNgFactory} from '../../../build/aot/test/angular-webpack/angular/module.ngfactory'; platformBrowser().bootstrapModuleFactory(ModuleNgFactory); test/angular-webpack/angular/bundle.ts000066400000000000000000000004651516112644000203570ustar00rootroot00000000000000import 'corifeus-web/src/bundle'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { enableProdMode } from '@angular/core'; import {Module} from './module'; if (process.env.ENV === 'production') { enableProdMode(); } platformBrowserDynamic().bootstrapModule(Module); test/angular-webpack/angular/module.ts000066400000000000000000000013471516112644000203730ustar00rootroot00000000000000import { NgModule, CUSTOM_ELEMENTS_SCHEMA, } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { CorifeusMaterialModule } from 'corifeus-web-material' import {Page } from './page'; import { CompileModule, } from '../../../src'; @NgModule({ imports: [ BrowserModule, CorifeusMaterialModule, CompileModule.forRoot({ module: { schemas: [CUSTOM_ELEMENTS_SCHEMA], declarations: [], imports: [ CorifeusMaterialModule ], } }) ], declarations: [ Page, ], providers: [ ], bootstrap: [ Page ] }) export class Module { }; test/angular-webpack/angular/page.ts000066400000000000000000000072371516112644000200260ustar00rootroot00000000000000import { Component, Injectable, ViewChild, ViewContainerRef, OnInit, NgModule, CUSTOM_ELEMENTS_SCHEMA, OnDestroy } from '@angular/core'; import {CompileService } from '../../../src'; @Component({ selector: 'p3x-compile-test', template: ` sss


Hidden
(you should nothing above, only hidden)

Visible
` }) @Injectable() export class Page implements OnInit, OnDestroy { @ViewChild('container', {read: ViewContainerRef}) container: ViewContainerRef; @ViewChild('container2', {read: ViewContainerRef}) container2: ViewContainerRef; data1: string; data2: string; data3: string = 'here content of your file'; data4: string = '' counter1 : number = 0; counter2 : number = 0; interval: any; constructor( private compileHtmlService: CompileService ) { } private async update1() { this.counter1++; this.data1 = `
Service
Click me via a service!
{{ context.counter1}}
`; Promise.all([ this.compileHtmlService.compile({ template: this.data1, container: this.container, context: this, onCompiled: (cmp : any) => { console.log('container1 compiled, same template '); } }) , this.compileHtmlService.compile({ template: this.data1, container: this.container2, context: this, onCompiled: (cmp : any) => { console.log('container2 compiled, same template'); } }) ]) } private update2() { this.counter2++; this.data2 = `
Attribute
Click me via an attribute!
{{ context.counter2}}
`; } ngOnInit() { this.update1(); this.update2(); let is = false; let newData = '123'; let defaultData = ''; let count = 0; /* this.interval = setInterval(() => { is = !is; if (is) { count++; defaultData = defaultData + newData; this.data3 = defaultData + defaultData; if (count > 10) { count = 0; defaultData = newData; } } else { this.data3 = '
321
' } }, 1000) */ } ngOnDestroy() { clearInterval(this.interval); } }test/angular-webpack/angular/polyfills.ts000066400000000000000000000000451516112644000211150ustar00rootroot00000000000000import 'corifeus-web/src/polyfills'; test/angular-webpack/index.html000066400000000000000000000003361516112644000170770ustar00rootroot00000000000000 angular-compile-html tsconfig.aot.json000066400000000000000000000013671516112644000143560ustar00rootroot00000000000000{ "compilerOptions": { "skipLibCheck": true, "outDir": "build/aot", "target": "es5", "module": "commonjs", "moduleResolution": "node", "sourceMap": false, "emitDecoratorMetadata": true, "experimentalDecorators": true, "noImplicitAny": true, "suppressImplicitAnyIndexErrors": true, "lib": [ "es5", "es6", "dom", "es2015.collection", "es2015.promise", "es2015.core" ] }, "includes": [ "src/angular/**/*", "test/angular-webpack/**/*" ], "exclude": [ "node_modules", "src/angular/boot.ts", "test/angular-webpack/angular/boot.ts", "build/browser" ], "angularCompilerOptions": { "genDir": "./build/aot", "skipMetadataEmit" : true } }tsconfig.build.json000066400000000000000000000015321516112644000146640ustar00rootroot00000000000000{ "compilerOptions": { "baseUrl": ".", "declaration": true, "stripInternal": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "noImplicitAny": true, "strictNullChecks": true, "noFallthroughCasesInSwitch": true, "module": "commonjs", "moduleResolution": "node", "outDir": "./dist", "paths": { }, "rootDir": ".", "sourceMap": true, "inlineSources": true, "target": "es5", "skipLibCheck": true, "lib": ["es2015", "dom"], // don't auto-discover @types/node, it results in a ///