├── .gitignore ├── LICENSE ├── README.md ├── cli.js ├── example ├── index.html ├── inner-test │ ├── inner-test.component.css │ ├── inner-test.component.html │ ├── inner-test.component.spec.ts │ └── inner-test.component.ts ├── sub-child-test │ ├── sub-child-test.component.css │ ├── sub-child-test.component.html │ ├── sub-child-test.component.spec.ts │ └── sub-child-test.component.ts ├── sub-child-test2 │ ├── sub-child-test2.component.css │ ├── sub-child-test2.component.html │ ├── sub-child-test2.component.spec.ts │ └── sub-child-test2.component.ts └── test │ ├── test.component.css │ ├── test.component.html │ ├── test.component.spec.ts │ └── test.component.ts ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | .vscode -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Oleksii Okhrymenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Create Angular Components 2 | Tool that allows you to create Angular (10+) components from HTML 3 | 4 | # Install 5 | ``` 6 | npm install -g create-angular-components 7 | ``` 8 | 9 | # Prepare 10 | Add *data-component* attribute for every component in your markup 11 | PS: Use UpperCamelCase 12 | ```html 13 |
14 |

Test

15 |
16 | content 17 |
18 | content 19 |
20 |
21 | content2 22 |
23 |
24 |
25 | ``` 26 | 27 | # Use 28 | ``` 29 | cd example 30 | cac index.html 31 | # Generated 4 components, into /Users/UserName/example 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var program = require('commander'); 3 | var process = require('process'); 4 | var path = require('path'); 5 | var fse = require('fs-extra'); 6 | var package = require('./package.json'); 7 | var cac = require('./index'); 8 | 9 | program 10 | .description(package.description) 11 | .arguments('') 12 | .action(function (file) { 13 | var fileText = fse.readFileSync(file, 'utf8'); 14 | var components = cac.getComponentsFromHtml(fileText); 15 | var generatedCount = 0; 16 | 17 | components.forEach(function(component){ 18 | var targetPath = path.join(process.cwd(), component.dashedName); 19 | fse.removeSync(targetPath); 20 | fse.mkdirSync(targetPath); 21 | 22 | var tsFilePath = path.join(targetPath, component.dashedName + '.component.ts'); 23 | var cssFilePath = path.join(targetPath, component.dashedName + '.component.css'); 24 | var htmlFilePath = path.join(targetPath, component.dashedName + '.component.html'); 25 | var specFilePath = path.join(targetPath, component.dashedName + '.component.spec.ts'); 26 | 27 | fse.writeFileSync(tsFilePath, component.ts, 'utf8'); 28 | fse.writeFileSync(cssFilePath, component.css, 'utf8'); 29 | fse.writeFileSync(htmlFilePath, component.html, 'utf8'); 30 | fse.writeFileSync(specFilePath, component.spec, 'utf8'); 31 | generatedCount++; 32 | }); 33 | 34 | console.log('Generated ' + generatedCount + ' components, into ' + process.cwd()); 35 | }) 36 | .version(package.version) 37 | .parse(process.argv); 38 | 39 | // Check the program.args obj - if none, show help 40 | if (program.args.length === 0) { 41 | program.help(); 42 | } -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
11 |

Test

12 |
13 | content 14 |
15 | content 16 |
17 |
18 | content2 19 |
20 |
21 |
22 | 23 | -------------------------------------------------------------------------------- /example/inner-test/inner-test.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obenjiro/create-angular-components/7cfcb7c2d4bb00abf894fc30551b917a00450a4b/example/inner-test/inner-test.component.css -------------------------------------------------------------------------------- /example/inner-test/inner-test.component.html: -------------------------------------------------------------------------------- 1 |
2 | content 3 | 4 | 5 |
-------------------------------------------------------------------------------- /example/inner-test/inner-test.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { InnerTestComponent } from './inner-test.component'; 4 | 5 | describe('InnerTestComponent', () => { 6 | let component: InnerTestComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ InnerTestComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(InnerTestComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /example/inner-test/inner-test.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'inner-test', 5 | templateUrl: './inner-test.component.html', 6 | styleUrls: ['./inner-test.component.css'] 7 | }) 8 | export class InnerTestComponent { 9 | constructor () {} 10 | } 11 | -------------------------------------------------------------------------------- /example/sub-child-test/sub-child-test.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obenjiro/create-angular-components/7cfcb7c2d4bb00abf894fc30551b917a00450a4b/example/sub-child-test/sub-child-test.component.css -------------------------------------------------------------------------------- /example/sub-child-test/sub-child-test.component.html: -------------------------------------------------------------------------------- 1 |
2 | content 3 |
-------------------------------------------------------------------------------- /example/sub-child-test/sub-child-test.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SubChildTestComponent } from './sub-child-test.component'; 4 | 5 | describe('SubChildTestComponent', () => { 6 | let component: SubChildTestComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SubChildTestComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SubChildTestComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /example/sub-child-test/sub-child-test.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'sub-child-test', 5 | templateUrl: './sub-child-test.component.html', 6 | styleUrls: ['./sub-child-test.component.css'] 7 | }) 8 | export class SubChildTestComponent { 9 | constructor () {} 10 | } 11 | -------------------------------------------------------------------------------- /example/sub-child-test2/sub-child-test2.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obenjiro/create-angular-components/7cfcb7c2d4bb00abf894fc30551b917a00450a4b/example/sub-child-test2/sub-child-test2.component.css -------------------------------------------------------------------------------- /example/sub-child-test2/sub-child-test2.component.html: -------------------------------------------------------------------------------- 1 |
2 | content2 3 |
-------------------------------------------------------------------------------- /example/sub-child-test2/sub-child-test2.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SubChildTest2Component } from './sub-child-test2.component'; 4 | 5 | describe('SubChildTest2Component', () => { 6 | let component: SubChildTest2Component; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SubChildTest2Component ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SubChildTest2Component); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /example/sub-child-test2/sub-child-test2.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'sub-child-test2', 5 | templateUrl: './sub-child-test2.component.html', 6 | styleUrls: ['./sub-child-test2.component.css'] 7 | }) 8 | export class SubChildTest2Component { 9 | constructor () {} 10 | } 11 | -------------------------------------------------------------------------------- /example/test/test.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obenjiro/create-angular-components/7cfcb7c2d4bb00abf894fc30551b917a00450a4b/example/test/test.component.css -------------------------------------------------------------------------------- /example/test/test.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Test

3 | 4 |
-------------------------------------------------------------------------------- /example/test/test.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TestComponent } from './test.component'; 4 | 5 | describe('TestComponent', () => { 6 | let component: TestComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ TestComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TestComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /example/test/test.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'test', 5 | templateUrl: './test.component.html', 6 | styleUrls: ['./test.component.css'] 7 | }) 8 | export class TestComponent { 9 | constructor () {} 10 | } 11 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var jsdom = require('jsdom'); 2 | var dashify = require('dashify'); 3 | var JSDOM = jsdom.JSDOM; 4 | 5 | var getCss = function() { 6 | // TODO (we can use BEM here) 7 | return ''; 8 | } 9 | 10 | var getTsCode = function(name, dashedName) { 11 | return `import { Component } from '@angular/core'; 12 | 13 | @Component({ 14 | selector: '${dashedName}', 15 | templateUrl: './${dashedName}.component.html', 16 | styleUrls: ['./${dashedName}.component.css'] 17 | }) 18 | export class ${name}Component { 19 | constructor () {} 20 | } 21 | ` 22 | } 23 | 24 | var getSpec = function(name, dashedName) { 25 | return `import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 26 | 27 | import { ${name}Component } from './${dashedName}.component'; 28 | 29 | describe('${name}Component', () => { 30 | let component: ${name}Component; 31 | let fixture: ComponentFixture<${name}Component>; 32 | 33 | beforeEach(async(() => { 34 | TestBed.configureTestingModule({ 35 | declarations: [ ${name}Component ] 36 | }) 37 | .compileComponents(); 38 | })); 39 | 40 | beforeEach(() => { 41 | fixture = TestBed.createComponent(${name}Component); 42 | component = fixture.componentInstance; 43 | fixture.detectChanges(); 44 | }); 45 | 46 | it('should be created', () => { 47 | expect(component).toBeTruthy(); 48 | }); 49 | }); 50 | ` 51 | } 52 | 53 | var generator = { 54 | 55 | getComponentsFromHtml: function(fileText) { 56 | var that = this; 57 | var dom = new JSDOM(fileText); 58 | var nodes = dom.window.document.querySelectorAll('[data-component]'); 59 | var nodesArray = Array.prototype.slice.call(nodes); 60 | var components = nodesArray.reverse().map(function(node){ 61 | return that.getComponentFromNode(node); 62 | }); 63 | return components; 64 | }, 65 | 66 | getComponentFromNode: function(node) { 67 | node = node.cloneNode(true); 68 | var name = node.getAttribute('data-component'); 69 | var dashedName = dashify(name); 70 | 71 | var children = node.querySelectorAll('[data-component]'); 72 | for (var i = 0; i < children.length; i++) { 73 | var cmp = this.getComponentFromNode(children[i]); 74 | children[i].outerHTML = '<' + cmp.dashedName + '>' + ''; 75 | } 76 | 77 | node.removeAttribute('data-component'); 78 | 79 | return { 80 | name: name, 81 | dashedName: dashedName, 82 | ts: getTsCode(name, dashedName), 83 | spec: getSpec(name, dashedName), 84 | css: getCss(), 85 | html: node.outerHTML, 86 | } 87 | } 88 | }; 89 | 90 | module.exports = generator; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-angular-components", 3 | "version": "1.0.0", 4 | "description": "Tool that allows you to create Angular (4+) components from HTML", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/aiboy/create-angular-components.git" 12 | }, 13 | "author": "Alexey Okhrimenko", 14 | "license": "MIT", 15 | "bin": { 16 | "create-angular-components": "./cli.js", 17 | "cac": "./cli.js" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/aiboy/create-angular-components/issues" 21 | }, 22 | "homepage": "https://github.com/aiboy/create-angular-components#readme", 23 | "dependencies": { 24 | "commander": "^6.0.0", 25 | "dashify": "^2.0.0", 26 | "fs-extra": "^9.0.1", 27 | "jsdom": "^16.2.2" 28 | } 29 | } 30 | --------------------------------------------------------------------------------