mirror of
https://github.com/bobwen-dev/react-templates
synced 2025-04-12 00:56:39 +02:00
improve cli, eslint quotes
This commit is contained in:
parent
a8079e1b7b
commit
e4c5d6e613
@ -118,7 +118,7 @@
|
|||||||
"new-cap": 2,
|
"new-cap": 2,
|
||||||
"semi": 2,
|
"semi": 2,
|
||||||
"use-isnan": 2,
|
"use-isnan": 2,
|
||||||
"quotes": [0, "single"],
|
"quotes": [1, "single", "avoid-escape"],
|
||||||
"max-params": [0, 3],
|
"max-params": [0, 3],
|
||||||
"max-statements": [0, 10],
|
"max-statements": [0, 10],
|
||||||
"complexity": [0, 11],
|
"complexity": [0, 11],
|
||||||
|
40
src/cli.js
40
src/cli.js
@ -1,28 +1,48 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
/**
|
/**
|
||||||
* Created by idok on 11/10/14.
|
* Created by idok on 11/10/14.
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
var fs = require('fs');
|
//var fs = require('fs');
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var reactTemplates = require('./reactTemplates');
|
var reactTemplates = require('./reactTemplates');
|
||||||
|
var pkg = require('../package.json');
|
||||||
|
|
||||||
if (process.argv.length > 2) {
|
if (process.argv.length > 2) {
|
||||||
_.forEach(process.argv.slice(2), handleSingleFile);
|
if (process.argv.indexOf('-v') !== -1 || process.argv.indexOf('--version') !== -1) {
|
||||||
|
console.log(pkg.version);
|
||||||
|
} else if (process.argv.indexOf('-h') !== -1 || process.argv.indexOf('--help') !== -1) {
|
||||||
|
printHelp();
|
||||||
} else {
|
} else {
|
||||||
console.log("Usage:node reactTemplates.js <filename>");
|
_.forEach(process.argv.slice(2), handleSingleFile);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printHelp();
|
||||||
|
}
|
||||||
|
|
||||||
|
function printHelp() {
|
||||||
|
console.log(pkg.description);
|
||||||
|
console.log('');
|
||||||
|
console.log('Usage:');
|
||||||
|
console.log(' $ node reactTemplates.js <filename>');
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSingleFile(filename) {
|
function handleSingleFile(filename) {
|
||||||
if (path.extname(filename) !== ".rt") {
|
if (path.extname(filename) !== '.rt') {
|
||||||
console.log('invalid file, only handle rt files');
|
console.log('invalid file, only handle rt files');
|
||||||
return;// only handle html files
|
return;// only handle html files
|
||||||
}
|
}
|
||||||
var html = fs.readFileSync(filename).toString();
|
// var html = fs.readFileSync(filename).toString();
|
||||||
if (!html.match(/\<\!doctype jsx/)) {
|
// if (!html.match(/\<\!doctype jsx/)) {
|
||||||
console.log('invalid file, missing header');
|
// console.log('invalid file, missing header');
|
||||||
return;
|
// return;
|
||||||
|
// }
|
||||||
|
// var js = reactTemplates.convertTemplateToReact(html);
|
||||||
|
// fs.writeFileSync(filename + '.js', js);
|
||||||
|
try {
|
||||||
|
reactTemplates.convertFile(filename, filename + '.js');
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Error processing file: ' + filename + ', ' + e.description);
|
||||||
}
|
}
|
||||||
var js = reactTemplates.convertTemplateToReact(html);
|
|
||||||
fs.writeFileSync(filename + '.js', js);
|
|
||||||
}
|
}
|
@ -10,16 +10,16 @@ var React = require('react');
|
|||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
|
||||||
|
|
||||||
var repeatTemplate = _.template("_.map(<%= collection %>,function (<%= item %>,<%= item %>Index) {\n return <%= body %>}, this)");
|
var repeatTemplate = _.template('_.map(<%= collection %>,function (<%= item %>,<%= item %>Index) {\n return <%= body %>}, this)');
|
||||||
var ifTemplate = _.template("((<%= condition %>)?(<%= body %>):null)");
|
var ifTemplate = _.template('((<%= condition %>)?(<%= body %>):null)');
|
||||||
var classSetTemplate = _.template("React.addons.classSet(<%= classSet %>)");
|
var classSetTemplate = _.template('React.addons.classSet(<%= classSet %>)');
|
||||||
var tagTemplate = _.template("<%= name %>.apply(this,_.flatten([<%= props %>].concat([<%= children %>])))");
|
var tagTemplate = _.template('<%= name %>.apply(this,_.flatten([<%= props %>].concat([<%= children %>])))');
|
||||||
var commentTemplate = _.template(" /* <%= data %> */ ");
|
var commentTemplate = _.template(' /* <%= data %> */ ');
|
||||||
var templateTemplate = _.template("define([<%= requirePaths %>], function (<%= requireNames %>) {\n <%= injectedFunctions %>\nreturn function(){ return <%= body %>};\n});");
|
var templateTemplate = _.template("define([<%= requirePaths %>], function (<%= requireNames %>) {\n'use strict';\n <%= injectedFunctions %>\nreturn function(){ return <%= body %>};\n});");
|
||||||
|
|
||||||
var templateProp = "rt-repeat";
|
var templateProp = 'rt-repeat';
|
||||||
var ifProp = "rt-if";
|
var ifProp = 'rt-if';
|
||||||
var classSetProp = "rt-class";
|
var classSetProp = 'rt-class';
|
||||||
|
|
||||||
var reactSupportedAttributes = ['accept', 'acceptCharset', 'accessKey', 'action', 'allowFullScreen', 'allowTransparency', 'alt', 'async', 'autoComplete', 'autoPlay', 'cellPadding', 'cellSpacing', 'charSet', 'checked', 'classID', 'className', 'cols', 'colSpan', 'content', 'contentEditable', 'contextMenu', 'controls', 'coords', 'crossOrigin', 'data', 'dateTime', 'defer', 'dir', 'disabled', 'download', 'draggable', 'encType', 'form', 'formNoValidate', 'frameBorder', 'height', 'hidden', 'href', 'hrefLang', 'htmlFor', 'httpEquiv', 'icon', 'id', 'label', 'lang', 'list', 'loop', 'manifest', 'max', 'maxLength', 'media', 'mediaGroup', 'method', 'min', 'multiple', 'muted', 'name', 'noValidate', 'open', 'pattern', 'placeholder', 'poster', 'preload', 'radioGroup', 'readOnly', 'rel', 'required', 'role', 'rows', 'rowSpan', 'sandbox', 'scope', 'scrolling', 'seamless', 'selected', 'shape', 'size', 'sizes', 'span', 'spellCheck', 'src', 'srcDoc', 'srcSet', 'start', 'step', 'style', 'tabIndex', 'target', 'title', 'type', 'useMap', 'value', 'width', 'wmode'];
|
var reactSupportedAttributes = ['accept', 'acceptCharset', 'accessKey', 'action', 'allowFullScreen', 'allowTransparency', 'alt', 'async', 'autoComplete', 'autoPlay', 'cellPadding', 'cellSpacing', 'charSet', 'checked', 'classID', 'className', 'cols', 'colSpan', 'content', 'contentEditable', 'contextMenu', 'controls', 'coords', 'crossOrigin', 'data', 'dateTime', 'defer', 'dir', 'disabled', 'download', 'draggable', 'encType', 'form', 'formNoValidate', 'frameBorder', 'height', 'hidden', 'href', 'hrefLang', 'htmlFor', 'httpEquiv', 'icon', 'id', 'label', 'lang', 'list', 'loop', 'manifest', 'max', 'maxLength', 'media', 'mediaGroup', 'method', 'min', 'multiple', 'muted', 'name', 'noValidate', 'open', 'pattern', 'placeholder', 'poster', 'preload', 'radioGroup', 'readOnly', 'rel', 'required', 'role', 'rows', 'rowSpan', 'sandbox', 'scope', 'scrolling', 'seamless', 'selected', 'shape', 'size', 'sizes', 'span', 'spellCheck', 'src', 'srcDoc', 'srcSet', 'start', 'step', 'style', 'tabIndex', 'target', 'title', 'type', 'useMap', 'value', 'width', 'wmode'];
|
||||||
var attributesMapping = {'class': 'className', 'rt-class': 'className'};
|
var attributesMapping = {'class': 'className', 'rt-class': 'className'};
|
||||||
@ -31,11 +31,11 @@ _.forEach(reactSupportedAttributes,function (attributeReactName) {
|
|||||||
|
|
||||||
|
|
||||||
function concatChildren(children) {
|
function concatChildren(children) {
|
||||||
var res = "";
|
var res = '';
|
||||||
var first = true;
|
var first = true;
|
||||||
_.forEach(children, function (child) {
|
_.forEach(children, function (child) {
|
||||||
if (child.indexOf(" /*") !== 0 && child) {
|
if (child.indexOf(' /*') !== 0 && child) {
|
||||||
res += (first ? "" : ",") + child;
|
res += (first ? '' : ',') + child;
|
||||||
first = false;
|
first = false;
|
||||||
} else {
|
} else {
|
||||||
res += child;
|
res += child;
|
||||||
@ -48,13 +48,13 @@ var curlyMap = {'{': 1, '}': -1};
|
|||||||
|
|
||||||
function convertText(txt) {
|
function convertText(txt) {
|
||||||
txt = txt.trim();
|
txt = txt.trim();
|
||||||
var res = "";
|
var res = '';
|
||||||
var first = true;
|
var first = true;
|
||||||
while (txt.indexOf('{') !== -1) {
|
while (txt.indexOf('{') !== -1) {
|
||||||
var start = txt.indexOf('{');
|
var start = txt.indexOf('{');
|
||||||
var pre = txt.substr(0,start);
|
var pre = txt.substr(0,start);
|
||||||
if (pre) {
|
if (pre) {
|
||||||
res += (first ? "" : "+") + JSON.stringify(pre);
|
res += (first ? '' : '+') + JSON.stringify(pre);
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
var curlyCounter = 1;
|
var curlyCounter = 1;
|
||||||
@ -62,15 +62,15 @@ function convertText(txt) {
|
|||||||
curlyCounter += curlyMap[txt.charAt(end)] || 0;
|
curlyCounter += curlyMap[txt.charAt(end)] || 0;
|
||||||
}
|
}
|
||||||
if (curlyCounter !== 0) {
|
if (curlyCounter !== 0) {
|
||||||
throw "Failed to parse text";
|
throw 'Failed to parse text';
|
||||||
} else {
|
} else {
|
||||||
res += (first ? "" : "+") + txt.substr(start + 1, end - start - 2);
|
res += (first ? '' : '+') + txt.substr(start + 1, end - start - 2);
|
||||||
first = false;
|
first = false;
|
||||||
txt = txt.substr(end);
|
txt = txt.substr(end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (txt) {
|
if (txt) {
|
||||||
res += (first ? "" : "+") + JSON.stringify(txt);
|
res += (first ? '' : '+') + JSON.stringify(txt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -86,57 +86,57 @@ function generateProps(node, context) {
|
|||||||
_.forOwn(node.attribs, function (val, key) {
|
_.forOwn(node.attribs, function (val, key) {
|
||||||
var propKey = attributesMapping[key.toLowerCase()] || key;
|
var propKey = attributesMapping[key.toLowerCase()] || key;
|
||||||
if (props.hasOwnProperty(propKey)) {
|
if (props.hasOwnProperty(propKey)) {
|
||||||
throw "duplicate definition of " + propKey + " " + JSON.stringify(node.attribs);
|
throw 'duplicate definition of ' + propKey + ' ' + JSON.stringify(node.attribs);
|
||||||
}
|
}
|
||||||
if (key.indexOf("on") === 0 && !isStringOnlyCode(val)) {
|
if (key.indexOf('on') === 0 && !isStringOnlyCode(val)) {
|
||||||
var funcParts = val.split("=>");
|
var funcParts = val.split('=>');
|
||||||
var evtParams = funcParts[0].replace("(", "").replace(")", "").trim();
|
var evtParams = funcParts[0].replace('(', '').replace(')', '').trim();
|
||||||
var funcBody = funcParts[1].trim();
|
var funcBody = funcParts[1].trim();
|
||||||
var generatedFuncName = "generated" + (context.injectedFunctions.length + 1);
|
var generatedFuncName = 'generated' + (context.injectedFunctions.length + 1);
|
||||||
var params = context.boundParams;
|
var params = context.boundParams;
|
||||||
if (evtParams.trim().length > 0) {
|
if (evtParams.trim().length > 0) {
|
||||||
params = params.concat(evtParams.trim());
|
params = params.concat(evtParams.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
var funcText = "function " + generatedFuncName + "(" + params.join(",");
|
var funcText = 'function ' + generatedFuncName + '(' + params.join(',');
|
||||||
funcText += ") {\n" + funcBody + "\n}\n";
|
funcText += ') {\n' + funcBody + '\n}\n';
|
||||||
context.injectedFunctions.push(funcText);
|
context.injectedFunctions.push(funcText);
|
||||||
props[propKey] = generatedFuncName + ".bind(" + (["this"].concat(context.boundParams)).join(",") + ")";
|
props[propKey] = generatedFuncName + '.bind(' + (['this'].concat(context.boundParams)).join(',') + ')';
|
||||||
} else if (key === "style" && !isStringOnlyCode(val)) {
|
} else if (key === 'style' && !isStringOnlyCode(val)) {
|
||||||
var styleParts = val.trim().split(";");
|
var styleParts = val.trim().split(';');
|
||||||
styleParts = _.compact(_.map(styleParts, function (str) {
|
styleParts = _.compact(_.map(styleParts, function (str) {
|
||||||
str = str.trim();
|
str = str.trim();
|
||||||
if (!str || str.indexOf(':') === -1) {
|
if (!str || str.indexOf(':') === -1) {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
var res = str.split(":");
|
var res = str.split(':');
|
||||||
res[0] = res[0].trim();
|
res[0] = res[0].trim();
|
||||||
if (res[0].indexOf("-") != -1) {
|
if (res[0].indexOf('-') !== -1) {
|
||||||
res[0] = "\"" + res[0] + "\"";
|
res[0] = '"' + res[0] + '"';
|
||||||
}
|
}
|
||||||
res[1] = res[1].trim();
|
res[1] = res[1].trim();
|
||||||
return res;
|
return res;
|
||||||
}));
|
}));
|
||||||
var styleArray = [];
|
var styleArray = [];
|
||||||
_.forEach(styleParts, function (stylePart) {
|
_.forEach(styleParts, function (stylePart) {
|
||||||
styleArray.push(stylePart[0] + " : " + convertText(stylePart[1]))
|
styleArray.push(stylePart[0] + ' : ' + convertText(stylePart[1]));
|
||||||
});
|
});
|
||||||
props[propKey] = "{" + styleArray.join(",") + "}";
|
props[propKey] = '{' + styleArray.join(',') + '}';
|
||||||
} else if (key === classSetProp) {
|
} else if (key === classSetProp) {
|
||||||
props[propKey] = classSetTemplate({classSet: val});
|
props[propKey] = classSetTemplate({classSet: val});
|
||||||
} else if (key.indexOf("rt-") !== 0) {
|
} else if (key.indexOf('rt-') !== 0) {
|
||||||
props[propKey] = convertText(val);
|
props[propKey] = convertText(val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return "{" + _.map(props, function (val, key) {
|
return '{' + _.map(props, function (val, key) {
|
||||||
return JSON.stringify(key) + " : " + val;
|
return JSON.stringify(key) + ' : ' + val;
|
||||||
}).join(",") + "}";
|
}).join(',') + '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertTagNameToConstructor(tagName) {
|
function convertTagNameToConstructor(tagName) {
|
||||||
return React.DOM.hasOwnProperty(tagName) ? "React.DOM." + tagName : tagName;
|
return React.DOM.hasOwnProperty(tagName) ? 'React.DOM.' + tagName : tagName;
|
||||||
}
|
}
|
||||||
|
|
||||||
function defaultContext() {
|
function defaultContext() {
|
||||||
@ -153,7 +153,7 @@ function addIfNotThere(array, obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function convertHtmlToReact(node, context) {
|
function convertHtmlToReact(node, context) {
|
||||||
if (node.type === "tag") {
|
if (node.type === 'tag') {
|
||||||
context = {
|
context = {
|
||||||
boundParams: _.clone(context.boundParams),
|
boundParams: _.clone(context.boundParams),
|
||||||
injectedFunctions: context.injectedFunctions
|
injectedFunctions: context.injectedFunctions
|
||||||
@ -161,10 +161,10 @@ function convertHtmlToReact(node, context) {
|
|||||||
|
|
||||||
var data = {name: convertTagNameToConstructor(node.name)};
|
var data = {name: convertTagNameToConstructor(node.name)};
|
||||||
if (node.attribs[templateProp]) {
|
if (node.attribs[templateProp]) {
|
||||||
data.item = node.attribs[templateProp].split(" in ")[0].trim();
|
data.item = node.attribs[templateProp].split(' in ')[0].trim();
|
||||||
data.collection = node.attribs[templateProp].split(" in ")[1].trim();
|
data.collection = node.attribs[templateProp].split(' in ')[1].trim();
|
||||||
addIfNotThere(context.boundParams, data.item);
|
addIfNotThere(context.boundParams, data.item);
|
||||||
addIfNotThere(context.boundParams, data.item + "Index");
|
addIfNotThere(context.boundParams, data.item + 'Index');
|
||||||
}
|
}
|
||||||
data.props = generateProps(node, context);
|
data.props = generateProps(node, context);
|
||||||
if (node.attribs[ifProp]) {
|
if (node.attribs[ifProp]) {
|
||||||
@ -183,13 +183,13 @@ function convertHtmlToReact(node, context) {
|
|||||||
data.body = ifTemplate(data);
|
data.body = ifTemplate(data);
|
||||||
}
|
}
|
||||||
return data.body;
|
return data.body;
|
||||||
} else if (node.type === "comment") {
|
} else if (node.type === 'comment') {
|
||||||
return (commentTemplate(node));
|
return (commentTemplate(node));
|
||||||
} else if (node.type === "text") {
|
} else if (node.type === 'text') {
|
||||||
if (node.data.trim()) {
|
if (node.data.trim()) {
|
||||||
return convertText(node.data.trim());
|
return convertText(node.data.trim());
|
||||||
}
|
}
|
||||||
return "";
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,31 +201,37 @@ function extractDefinesFromJSXTag(html, defines) {
|
|||||||
reqStr = reqStr.replace(/\s*(\w+)\s*\=\s*\"([^\"]*)\"\s*/, function(full, varName, reqPath) {
|
reqStr = reqStr.replace(/\s*(\w+)\s*\=\s*\"([^\"]*)\"\s*/, function(full, varName, reqPath) {
|
||||||
defines[reqPath] = varName;
|
defines[reqPath] = varName;
|
||||||
match = true;
|
match = true;
|
||||||
return "";
|
return '';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return "";
|
return '';
|
||||||
});
|
});
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} html
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
function convertTemplateToReact(html) {
|
function convertTemplateToReact(html) {
|
||||||
var defines = {react: "React", lodash: "_"};
|
// var x = cheerio.load(html);
|
||||||
|
var defines = {react: 'React', lodash: '_'};
|
||||||
html = extractDefinesFromJSXTag(html, defines);
|
html = extractDefinesFromJSXTag(html, defines);
|
||||||
var rootNode = cheerio.load(html.trim(), {lowerCaseTags: false, lowerCaseAttributeNames: false, xmlMode: true});
|
var rootNode = cheerio.load(html.trim(), {lowerCaseTags: false, lowerCaseAttributeNames: false, xmlMode: true});
|
||||||
var context = defaultContext();
|
var context = defaultContext();
|
||||||
var body = convertHtmlToReact(rootNode.root()[0].children[0], context);
|
var body = convertHtmlToReact(rootNode.root()[0].children[0], context);
|
||||||
var requirePaths = _(defines).keys().map(function (reqName) {return '"' + reqName + '"';}).value().join(",");
|
var requirePaths = _(defines).keys().map(function (reqName) { return '"' + reqName + '"'; }).value().join(',');
|
||||||
var requireVars = _(defines).values().value().join(",");
|
var requireVars = _(defines).values().value().join(',');
|
||||||
var data = {body: body, injectedFunctions: "", requireNames: requireVars, requirePaths: requirePaths};
|
var data = {body: body, injectedFunctions: '', requireNames: requireVars, requirePaths: requirePaths};
|
||||||
data.injectedFunctions = context.injectedFunctions.join("\n");
|
data.injectedFunctions = context.injectedFunctions.join('\n');
|
||||||
var code = templateTemplate(data);
|
var code = templateTemplate(data);
|
||||||
try {
|
try {
|
||||||
var tree = esprima.parse(code, {range: true, tokens: true, comment: true});
|
var tree = esprima.parse(code, {range: true, tokens: true, comment: true});
|
||||||
tree = escodegen.attachComments(tree, tree.comments, tree.tokens);
|
tree = escodegen.attachComments(tree, tree.comments, tree.tokens);
|
||||||
code = escodegen.generate(tree, {comment: true});
|
code = escodegen.generate(tree, {comment: true});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
// TODO error handling
|
||||||
|
console.log(e);
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
@ -241,8 +247,7 @@ function convertFile(source, target) {
|
|||||||
// }
|
// }
|
||||||
var html = fs.readFileSync(source).toString();
|
var html = fs.readFileSync(source).toString();
|
||||||
if (!html.match(/\<\!doctype jsx/i)) {
|
if (!html.match(/\<\!doctype jsx/i)) {
|
||||||
console.log('invalid file, missing header');
|
throw new Error('invalid file, missing header');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
var js = convertTemplateToReact(html);
|
var js = convertTemplateToReact(html);
|
||||||
fs.writeFileSync(target, js);
|
fs.writeFileSync(target, js);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user