rocket-translator
Version:
Translate your HTML files to React.js and Vue.js
335 lines (278 loc) • 8.37 kB
JavaScript
const StateManagement = require("./StateManagement");
const JavaScriptEvents = require("../../const/Events.json");
const Utils = require("../../commons/utils");
const {isUpperCase} = Utils;
/**
* Class Angular State Management
*
* @class
* @extends StateManagement
*/
class AngularStateManagement extends StateManagement {
/**
* Get Component Data (getter)
*
* @public
* @return {string}
*/
get componentData() {
/*
States
lifecycles
Props
Methods
Computeds
watchers
*/
const haveStates = this.states.length > 0;
const haveProps = this.props.length > 0;
// eslint-disable-next-line no-unused-vars
const haveLifecycles = this.lifecycle.length > 0;
const haveComputed = this.computed.length > 0;
const haveMethods = this.methods.length > 0;
// eslint-disable-next-line no-unused-vars
const haveWatchers = this.watchers.length > 0;
var states = "";
var methods = "";
var props = "";
var computed = "";
if(haveStates) {
const mappedStates = this.states.map(e => {
if(typeof e === "object")
return `${e.key} = ${this._toString(e.value)};`;
return `${e} = "";`;
});
states = `${mappedStates.join("\n\t")}\n\n\t`;
}
if(haveMethods){
const mappedMethods = this.methods.map(({name, content}) => {
return `${name}${content}`;
});
methods = `${mappedMethods.join("\n\t")}\n\n\t`;
}
if (haveProps) {
const mappedProps = this.props.map(e => `@Input() ${e} : string;`);
props = `${mappedProps.join("\n\t")}\n\n\t`;
}
if (haveComputed) {
const mappedComputed = this.computed.map(({name, content}) => `get ${name}(): string ${content.replace(/\(.*\)/, "")}`);
computed = `${mappedComputed.join("\n\t")}\n\t`;
}
return `${props}${states}${methods}${computed}`;
}
/**
* Filter HTML
*
* @public
* @param {string} html
*
* @return {string}
*
*/
filterHTML(html) {
return html
/*Replace All Quotes with single quotes*/
.replace(/"/g, "'")
/*Filter html data*/
.split(/\{(?=\w*)/g)
.map((e, i) => {
if (i === 0)
return e;
return `{{${e.replace(/(\s*-.*\})/g, "}}")}`;
})
.join("")
/*Filter HTML Events*/
.split(new RegExp(`on(?=${JavaScriptEvents.join("|")})`))
.map((e, i) => {
if (i > 0) {
const event = e.match(/\w*(?==)/)[0];
return `(${event})${e.replace(event, "")}`;
}
return e;
})
.join("")
/*Filter Components Declaration*/
.split(/<(?=[A-Z]\w*)/)
.map((e, i) => {
if (i === 0)
return e;
let componentName = e.match(/^\w*/)[0];
let newName = this.generateComponentName(componentName);
return e.replace(/^\w*/, `${newName}-root`).replace(/\s*\/>/, `></${newName}-root>`);
})
.join("<")
/*Bind Directives*/
.split(/:(?=\w*=)/)
.map((content, i) => {
if (i > 0) {
const bindSimpleOrWithTypeRegExp = /^\w*='(\w*(\s*-\s*\w*)*)'/;
const bindWithConditional = /^\w*='\s*\w*\s*(\?).*('|"|}|])\s*'/;
if (bindSimpleOrWithTypeRegExp.test(content)) {
const bindAttr = content.match(bindSimpleOrWithTypeRegExp)[0];
const attrName = bindAttr.match(/\w*/)[0];
content = content.replace(new RegExp(`^${attrName}`), `[${attrName}]`);
if (/prop/.test(bindAttr) || /state/.test(bindAttr))
return content.replace(/\s*-\s*\w*'/, "'");
return content;
}
else if (bindWithConditional.test(content)) {
const expression = content.match(bindWithConditional)[0];
const replacedQuotes = expression
.replace(/"/g, "'")
.replace("'", "\"")
.replace(/'$/, "}}");
return content
.replace(expression, replacedQuotes)
.replace("=\"", "={{");
}
}
//return content of index 0
return content;
})
.join("")
.split(/<(?=for\s*val=)/)
.map((e, i) => {
if (i > 0) {
const tagRegExp = /\s*tag=('|")\w*(-\w*)*('|")/;
var tagName = "div";
if (tagRegExp.test(e))
tagName = e.match(tagRegExp)[0]
.replace(/\s*tag=/, "")
.replace(/'|"/g, "");
const loopData = e.match(/\w*\s*in\s*\w*/)[0];
const dataSplitted = loopData.split(/\s*in\s*/);
const varName = dataSplitted[0];
const stateName = dataSplitted[1];
return e.replace(/for val=(?=.*>)/g, `${tagName} *ngFor=`)
.replace(/\/for(?=>)/g, `/${tagName}`)
.replace(tagRegExp, "")
.replace(loopData, `let ${varName} of ${stateName}`);
}
return e;
})
.join("<")
.split(/<(?=if\s*cond=)/)
.map((e, i) => {
if (i > 0) {
var haveElse = false;
var elseId;
const dataSplitted = e.split(/<(?=else)/);
const mappedData = dataSplitted.map(conditional => {
var data = conditional;
const tagRegExp = /\s*tag=('|")\w*(-\w*)*('|")/;
const conditionalTag = /^\w*(-\w*)*/.exec(conditional)[0];
const isElse = /^else\s*.*>/.test(conditional);
// TODO: Add Else If Support
//const isElseIf = /else-if\s*/.test(conditional);
haveElse = isElse;
var tagName = "div";
var haveTag = tagRegExp.test(conditional);
if (haveTag) {
tagName = e.match(tagRegExp)[0]
.replace(/\s*tag=/, "")
.replace(/'|"/g, "");
}
if (isElse) {
var id = ""; //Empty String to set a conditional ID
/*
* Generate ID
*/
for (let a = 0; a <= 3; a++) {
id += new String(Math.floor(Math.random()*10));
}
elseId = id;
tagName = haveTag ? tagName : "ng-template";
data = data
.replace(/^else.*>/, `${tagName} #elseBlock${id}>`)
.replace("</else>", `<${tagName}>`);
}
data = data
.replace(conditionalTag, tagName)
.replace(`</${conditionalTag}>`, `</${tagName}>`)
.replace(tagRegExp, "")
.replace(/cond=/, "*ngIf=");
return data;
});
if (haveElse) {
var mainIf = mappedData[0];
const cond = mainIf.match(/\*ngIf=('|").*('|")/)[0];
const newCond = cond.replace(/('|")$/, `; else elseBlock${elseId}'`);
mappedData[0] = mainIf.replace(cond, newCond);
}
return mappedData.join("<");
}
return e;
}).join("<")
.split("<component ").map((e, i) => {
if (i > 0) {
var name = e.match(/component-name=('|")\w*/)[0].replace(/component-name=('|")/, "");
name = this.generateComponentName(name);
const attributes = e.split(">")[0].split(/\s(?=\w*=')/).map((attr, ind) => {
if (ind > 0)
return attr.match(/^\w*/)[0];
return null;
}).filter(a => a);
const splitted = e.split("</component>");
var tag = splitted[0].split(/\r\n|\n|\r/)[0];
tag = tag.replace(/component-name=('|")\w*('|")/, `${name}-root`).replace(">", `></${name}-root>`) + splitted[1];
attributes.forEach(a => {
tag = tag.replace(new RegExp(`${a}(?==')`), `[${a}]`);
});
return tag;
}
return e;
})
.join("<");
}
/**
* Generate Component
*
* Take a Camel Case and return Kebab Case
*
* @param {String} name
*
* @return {String}
*/
generateComponentName(name) {
var newName = "";
for (let i = 0; i < name.length; i++) {
const letter = name[i];
if (isUpperCase(letter)) {
if (i === 0)
newName += letter.toLowerCase();
else
newName += `-${letter.toLowerCase()}`;
}
else
newName += letter;
}
return newName;
}
/**
* To String
*
* Get all and Return String
*
* @private
* @param {any} data
*
* @return {String}
*/
_toString(data){
const _isNull = data === null;
const _isUndefined = data === undefined;
// eslint-disable-next-line use-isnan
const _isNaN = data === NaN;
const _isInfinity = data === Infinity;
if (_isNull)
return "null";
if (_isNaN)
return "NaN";
if (_isInfinity)
return "Infinity";
if (_isUndefined)
return "undefined";
return JSON.stringify(data);
}
}
module.exports = AngularStateManagement;