mirror of
https://github.com/bobwen-dev/react-templates
synced 2025-04-12 00:56:39 +02:00
better error reporting, added column and enfOffset, deprecated index
This commit is contained in:
parent
f187062ed1
commit
2c79edf519
97
src/RTCodeError.js
Normal file
97
src/RTCodeError.js
Normal file
@ -0,0 +1,97 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @param {string} html
|
||||
* @param node
|
||||
* @return {{line: number, col: number}}}
|
||||
*/
|
||||
function getLine(html, node) {
|
||||
if (!node) {
|
||||
return {col: 1, line: 1};
|
||||
}
|
||||
var linesUntil = html.substring(0, node.startIndex).split('\n');
|
||||
return {line: linesUntil.length, col: linesUntil[linesUntil.length - 1].length + 1};
|
||||
}
|
||||
|
||||
//function getLine(node) {
|
||||
// if (!node) {
|
||||
// return 0;
|
||||
// }
|
||||
// var line = 0;
|
||||
// var prev = node.prev;
|
||||
// while (prev) {
|
||||
// var nl = prev.data.split('\n').length - 1;
|
||||
// line += nl;
|
||||
// prev = prev.prev;
|
||||
// }
|
||||
//
|
||||
// line += getLine(node.parent);
|
||||
// return line + 1;
|
||||
//}
|
||||
|
||||
//function RTCodeError(message, line) {
|
||||
// this.name = 'RTCodeError';
|
||||
// this.message = message || '';
|
||||
// this.line = line || -1;
|
||||
//}
|
||||
//RTCodeError.prototype = Error.prototype;
|
||||
|
||||
// Redefine properties on Error to be enumerable
|
||||
/*eslint no-extend-native:0*/
|
||||
Object.defineProperty(Error.prototype, 'message', {configurable: true, enumerable: true});
|
||||
Object.defineProperty(Error.prototype, 'stack', {configurable: true, enumerable: true});
|
||||
//Object.defineProperty(Error.prototype, 'line', { configurable: true, enumerable: true });
|
||||
|
||||
/**
|
||||
* @param {string} message
|
||||
* @param {number=} startOffset
|
||||
* @param {number=} endOffset
|
||||
* @param {number=} line
|
||||
* @param {number=} column
|
||||
* @constructor
|
||||
*/
|
||||
function RTCodeError(message, startOffset, endOffset, line, column) {
|
||||
Error.captureStackTrace(this, RTCodeError);
|
||||
this.name = 'RTCodeError';
|
||||
this.message = message || '';
|
||||
this.index = norm(startOffset);
|
||||
this.startOffset = norm(startOffset);
|
||||
this.endOffset = norm(endOffset);
|
||||
this.line = norm(line);
|
||||
this.column = norm(column);
|
||||
}
|
||||
|
||||
function norm(n) {
|
||||
return n === undefined ? -1 : n;
|
||||
}
|
||||
|
||||
RTCodeError.prototype = Object.create(Error.prototype);
|
||||
|
||||
RTCodeError.build = buildError;
|
||||
RTCodeError.norm = norm;
|
||||
|
||||
RTCodeError.prototype.toIssue = function () {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} msg
|
||||
* @param {*} context
|
||||
* @param {*} node
|
||||
* @return {RTCodeError}
|
||||
*/
|
||||
function buildError(msg, context, node) {
|
||||
var pos = getLine(context.html, node);
|
||||
var end;
|
||||
if (node.data) {
|
||||
end = node.startIndex + node.data.length;
|
||||
} else if (node.next) {
|
||||
end = node.next.startIndex;
|
||||
} else {
|
||||
end = context.html.length;
|
||||
}
|
||||
return new RTCodeError(msg, node.startIndex, end, pos.line, pos.col);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
RTCodeError: RTCodeError
|
||||
};
|
17
src/cli.js
17
src/cli.js
@ -57,25 +57,10 @@ function handleSingleFile(currentOptions, filename) {
|
||||
context.error('invalid file, only handle rt files', filename);
|
||||
return;// only handle html files
|
||||
}
|
||||
// var html = fs.readFileSync(filename).toString();
|
||||
// if (!html.match(/\<\!doctype jsx/)) {
|
||||
// console.log('invalid file, missing header');
|
||||
// return;
|
||||
// }
|
||||
// var js = reactTemplates.convertTemplateToReact(html);
|
||||
// fs.writeFileSync(filename + '.js', js);
|
||||
try {
|
||||
api.convertFile(filename, filename + '.js', currentOptions, context);
|
||||
} catch (e) {
|
||||
context.error(e.message, filename, e.line || -1, -1, e.index || -1);
|
||||
// if (defaultOptions.json) {
|
||||
// context.error(e.message, filename, e.line || -1, -1, e.index || -1);
|
||||
// console.log(JSON.stringify(context.getMessages(), undefined, 2));
|
||||
// } else {
|
||||
// console.log('Error processing file: ' + filename + ', ' + e.message + ' line: ' + e.line || -1);
|
||||
// }
|
||||
// if (defaultOptions.stack)
|
||||
// console.log(e.stack);
|
||||
context.error(e.message, filename, e.line, e.column, e.startOffset, e.endOffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* @typedef {{color: boolean, cwd: string, report: function(string), warn: function(string), getMessages: function():Array.<MESSAGE>}} CONTEXT
|
||||
*/
|
||||
/**
|
||||
* @typedef {{msg: string, level: MESSAGE_LEVEL, file: string}} MESSAGE
|
||||
* @typedef {{msg: string, level: MESSAGE_LEVEL, file: string,line:number,column:number,startOffset:number,endOffset:number}} MESSAGE
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -17,13 +17,19 @@ var MESSAGE_LEVEL = {
|
||||
};
|
||||
|
||||
var _ = require('lodash');
|
||||
var err = require('./RTCodeError');
|
||||
var norm = err.RTCodeError.norm;
|
||||
|
||||
|
||||
/**
|
||||
* @type {CONTEXT}
|
||||
*/
|
||||
var context = {
|
||||
/** @type {Array.<MESSAGE>} */
|
||||
messages: [],
|
||||
/** @type {boolean} */
|
||||
color: true,
|
||||
/** @type {string} */
|
||||
cwd: process.cwd(),
|
||||
report: function (msg) {
|
||||
console.log(msg);
|
||||
@ -34,11 +40,20 @@ var context = {
|
||||
warn: function (msg, file, line, column) {
|
||||
context.issue(MESSAGE_LEVEL.WARN, msg, file, line, column);
|
||||
},
|
||||
error: function (msg, file, line, column, index) {
|
||||
context.issue(MESSAGE_LEVEL.ERROR, msg, file, line, column, index);
|
||||
error: function (msg, file, line, column, startOffset, endOffset) {
|
||||
context.issue(MESSAGE_LEVEL.ERROR, msg, file, line, column, startOffset, endOffset);
|
||||
},
|
||||
issue: function (level, msg, file, line, column, index) {
|
||||
context.messages.push({level: level, msg: msg, file: file || null, line: line || -1, column: column || -1, index: index || -1});
|
||||
/**
|
||||
* @param {MESSAGE_LEVEL} level
|
||||
* @param {string} msg
|
||||
* @param {string} file
|
||||
* @param {number} line
|
||||
* @param {number} column
|
||||
* @param {number=} startOffset
|
||||
* @param {number=} endOffset
|
||||
*/
|
||||
issue: function (level, msg, file, line, column, startOffset, endOffset) {
|
||||
context.messages.push({level: level, msg: msg, file: file || null, line: norm(line), column: norm(column), index: norm(startOffset), startOffset: norm(startOffset), endOffset: norm(endOffset)});
|
||||
},
|
||||
getMessages: function () {
|
||||
return context.messages;
|
||||
|
@ -8,6 +8,8 @@ var esprima = require('esprima');
|
||||
var escodegen = require('escodegen');
|
||||
var reactDOMSupport = require('./reactDOMSupport');
|
||||
var stringUtils = require('./stringUtils');
|
||||
var rtError = require('./RTCodeError');
|
||||
var RTCodeError = rtError.RTCodeError;
|
||||
|
||||
var repeatTemplate = _.template('_.map(<%= collection %>,<%= repeatFunction %>.bind(<%= repeatBinds %>))');
|
||||
var ifTemplate = _.template('((<%= condition %>)?(<%= body %>):null)');
|
||||
@ -34,6 +36,10 @@ var propsProp = 'rt-props';
|
||||
|
||||
var defaultOptions = {modules: 'amd', version: false, force: false, format: 'stylish', targetVersion: '0.12.2'};
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @return {boolean}
|
||||
*/
|
||||
function shouldUseCreateElement(context) {
|
||||
switch (context.options.targetVersion) {
|
||||
case '0.11.2':
|
||||
@ -54,6 +60,10 @@ _.forEach(reactSupportedAttributes, function (attributeReactName) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @param children
|
||||
* @return {string}
|
||||
*/
|
||||
function concatChildren(children) {
|
||||
var res = '';
|
||||
_.forEach(children, function (child) {
|
||||
@ -66,8 +76,17 @@ function concatChildren(children) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @const
|
||||
*/
|
||||
var curlyMap = {'{': 1, '}': -1};
|
||||
|
||||
/**
|
||||
* @param node
|
||||
* @param context
|
||||
* @param {string} txt
|
||||
* @return {string}
|
||||
*/
|
||||
function convertText(node, context, txt) {
|
||||
var res = '';
|
||||
var first = true;
|
||||
@ -84,7 +103,7 @@ function convertText(node, context, txt) {
|
||||
curlyCounter += curlyMap[txt.charAt(end)] || 0;
|
||||
}
|
||||
if (curlyCounter !== 0) {
|
||||
throw buildError("Failed to parse text '" + txt + "'", context, node);
|
||||
throw RTCodeError.build("Failed to parse text '" + txt + "'", context, node);
|
||||
} else {
|
||||
var needsParens = start !== 0 || end !== txt.length - 1;
|
||||
res += (first ? '' : '+') + (needsParens ? '(' : '') + txt.substr(start + 1, end - start - 2) + (needsParens ? ')' : '');
|
||||
@ -99,6 +118,7 @@ function convertText(node, context, txt) {
|
||||
res = 'true';
|
||||
}
|
||||
|
||||
//validateJS(res, node, context);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -120,81 +140,18 @@ function generateInjectedFunc(context, namePrefix, body, params) {
|
||||
return generatedFuncName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} html
|
||||
* @param node
|
||||
* @return {number}
|
||||
*/
|
||||
function getLine(html, node) {
|
||||
if (!node) {
|
||||
return 0;
|
||||
}
|
||||
return html.substring(0, node.startIndex).split('\n').length - 1;
|
||||
}
|
||||
|
||||
//function getLine(node) {
|
||||
// if (!node) {
|
||||
// return 0;
|
||||
// }
|
||||
// var line = 0;
|
||||
// var prev = node.prev;
|
||||
// while (prev) {
|
||||
// var nl = prev.data.split('\n').length - 1;
|
||||
// line += nl;
|
||||
// prev = prev.prev;
|
||||
// }
|
||||
//
|
||||
// line += getLine(node.parent);
|
||||
// return line + 1;
|
||||
//}
|
||||
|
||||
//function RTCodeError(message, line) {
|
||||
// this.name = 'RTCodeError';
|
||||
// this.message = message || '';
|
||||
// this.line = line || -1;
|
||||
//}
|
||||
//RTCodeError.prototype = Error.prototype;
|
||||
|
||||
// Redefine properties on Error to be enumerable
|
||||
/*eslint no-extend-native:0*/
|
||||
Object.defineProperty(Error.prototype, 'message', { configurable: true, enumerable: true });
|
||||
Object.defineProperty(Error.prototype, 'stack', { configurable: true, enumerable: true });
|
||||
//Object.defineProperty(Error.prototype, 'line', { configurable: true, enumerable: true });
|
||||
|
||||
function RTCodeError(message, index, line) {
|
||||
Error.captureStackTrace(this, RTCodeError);
|
||||
this.name = 'RTCodeError';
|
||||
this.message = message || '';
|
||||
this.index = index || -1;
|
||||
this.line = line || -1;
|
||||
}
|
||||
|
||||
RTCodeError.prototype = Object.create(Error.prototype);
|
||||
|
||||
/**
|
||||
* @param {string} msg
|
||||
* @param {*} context
|
||||
* @param {*} node
|
||||
* @return {RTCodeError}
|
||||
*/
|
||||
function buildError(msg, context, node) {
|
||||
var line = getLine(context.html, node);
|
||||
return new RTCodeError(msg, node.startIndex, line);
|
||||
}
|
||||
|
||||
|
||||
function generateProps(node, context) {
|
||||
// console.log(node);
|
||||
var props = {};
|
||||
_.forOwn(node.attribs, function (val, key) {
|
||||
var propKey = attributesMapping[key.toLowerCase()] || key;
|
||||
if (props.hasOwnProperty(propKey)) {
|
||||
throw buildError('duplicate definition of ' + propKey + ' ' + JSON.stringify(node.attribs), context, node);
|
||||
throw RTCodeError.build('duplicate definition of ' + propKey + ' ' + JSON.stringify(node.attribs), context, node);
|
||||
}
|
||||
if (key.indexOf('on') === 0 && !isStringOnlyCode(val)) {
|
||||
var funcParts = val.split('=>');
|
||||
if (funcParts.length !== 2) {
|
||||
throw buildError("when using 'on' events, use lambda '(p1,p2)=>body' notation or use {} to return a callback function. error: [" + key + "='" + val + "']", context, node);
|
||||
throw RTCodeError.build("when using 'on' events, use lambda '(p1,p2)=>body' notation or use {} to return a callback function. error: [" + key + "='" + val + "']", context, node);
|
||||
}
|
||||
var evtParams = funcParts[0].replace('(', '').replace(')', '').trim();
|
||||
var funcBody = funcParts[1].trim();
|
||||
@ -276,22 +233,26 @@ function convertHtmlToReact(node, context) {
|
||||
_.each(node.attribs[scopeProp].split(';'), function (scopePart) {
|
||||
var scopeSubParts = scopePart.split(' as ');
|
||||
if (scopeSubParts.length < 2) {
|
||||
throw buildError("invalid scope part '" + scopePart + "'", context, node);
|
||||
throw RTCodeError.build("invalid scope part '" + scopePart + "'", context, node);
|
||||
}
|
||||
var scopeName = scopeSubParts[1].trim();
|
||||
validateJS(scopeName, node, context);
|
||||
stringUtils.addIfNotThere(context.boundParams, scopeName);
|
||||
data.scopeName += stringUtils.capitalize(scopeName);
|
||||
data.scopeMapping[scopeName] = scopeSubParts[0].trim();
|
||||
validateJS(data.scopeMapping[scopeName], node, context);
|
||||
});
|
||||
}
|
||||
|
||||
if (node.attribs[templateProp]) {
|
||||
var arr = node.attribs[templateProp].split(' in ');
|
||||
if (arr.length !== 2) {
|
||||
throw buildError("rt-repeat invalid 'in' expression '" + node.attribs[templateProp] + "'", context, node);
|
||||
throw RTCodeError.build("rt-repeat invalid 'in' expression '" + node.attribs[templateProp] + "'", context, node);
|
||||
}
|
||||
data.item = arr[0].trim();
|
||||
data.collection = arr[1].trim();
|
||||
validateJS(data.item, node, context);
|
||||
validateJS(data.collection, node, context);
|
||||
stringUtils.addIfNotThere(context.boundParams, data.item);
|
||||
stringUtils.addIfNotThere(context.boundParams, data.item + 'Index');
|
||||
}
|
||||
@ -303,7 +264,9 @@ function convertHtmlToReact(node, context) {
|
||||
data.condition = node.attribs[ifProp].trim();
|
||||
}
|
||||
data.children = node.children ? concatChildren(_.map(node.children, function (child) {
|
||||
return convertHtmlToReact(child, context);
|
||||
var code = convertHtmlToReact(child, context);
|
||||
validateJS(code, child, context);
|
||||
return code;
|
||||
})) : '';
|
||||
|
||||
if (hasNonSimpleChildren(node)) {
|
||||
@ -344,7 +307,7 @@ function convertHtmlToReact(node, context) {
|
||||
// return html;
|
||||
//}
|
||||
function isTag(node) {
|
||||
return node.type === 'tag';
|
||||
return node.type === 'tag';
|
||||
}
|
||||
|
||||
function handleSelfClosingHtmlTags(nodes) {
|
||||
@ -375,29 +338,29 @@ function convertTemplateToReact(html, options) {
|
||||
options = _.defaults({}, options, defaultOptions);
|
||||
var defines = {'react/addons': 'React', lodash: '_'};
|
||||
var context = defaultContext(html, options);
|
||||
var rootTags = _.filter(rootNode.root()[0].children, function (i) { return i.type === 'tag'; });
|
||||
var rootTags = _.filter(rootNode.root()[0].children, {type: 'tag'});
|
||||
rootTags = handleSelfClosingHtmlTags(rootTags);
|
||||
if (!rootTags || rootTags.length === 0) {
|
||||
throw new RTCodeError('Document should have a root element');
|
||||
}
|
||||
var firstTag = null;
|
||||
_.forEach(rootTags, function(tag) {
|
||||
_.forEach(rootTags, function (tag) {
|
||||
if (tag.name === 'rt-require') {
|
||||
if (!tag.attribs.dependency || !tag.attribs.as) {
|
||||
throw buildError("rt-require needs 'dependency' and 'as' attributes", context, tag);
|
||||
} else if (tag.children.length) {
|
||||
throw buildError('rt-require may have no children', context, tag);
|
||||
} else {
|
||||
defines[tag.attribs.dependency] = tag.attribs.as;
|
||||
}
|
||||
if (!tag.attribs.dependency || !tag.attribs.as) {
|
||||
throw RTCodeError.build("rt-require needs 'dependency' and 'as' attributes", context, tag);
|
||||
} else if (tag.children.length) {
|
||||
throw RTCodeError.build('rt-require may have no children', context, tag);
|
||||
} else {
|
||||
defines[tag.attribs.dependency] = tag.attribs.as;
|
||||
}
|
||||
} else if (firstTag === null) {
|
||||
firstTag = tag;
|
||||
firstTag = tag;
|
||||
} else {
|
||||
throw buildError('Document should have no more than a single root element', context, tag);
|
||||
throw RTCodeError.build('Document should have no more than a single root element', context, tag);
|
||||
}
|
||||
});
|
||||
if (firstTag === null) {
|
||||
throw buildError('Document should have a single root element', context, rootNode.root()[0]);
|
||||
throw RTCodeError.build('Document should have a single root element', context, rootNode.root()[0]);
|
||||
}
|
||||
var body = convertHtmlToReact(firstTag, context);
|
||||
var requirePaths = _(defines).keys().map(function (reqName) { return '"' + reqName + '"'; }).value().join(',');
|
||||
@ -426,6 +389,19 @@ function generate(data, options) {
|
||||
return templatePJSTemplate(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} code
|
||||
* @param node
|
||||
* @param context
|
||||
*/
|
||||
function validateJS(code, node, context) {
|
||||
try {
|
||||
esprima.parse(code);
|
||||
} catch (e) {
|
||||
throw RTCodeError.build(e.description, context, node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @return {string}
|
||||
@ -438,5 +414,7 @@ module.exports = {
|
||||
convertTemplateToReact: convertTemplateToReact,
|
||||
RTCodeError: RTCodeError,
|
||||
normalizeName: normalizeName,
|
||||
_test: {}
|
||||
_test: {
|
||||
convertText: convertText
|
||||
}
|
||||
};
|
||||
|
6
test/data/invalid-brace.rt
Normal file
6
test/data/invalid-brace.rt
Normal file
@ -0,0 +1,6 @@
|
||||
<!--suppress CheckEmptyScriptTag -->
|
||||
<rt-require dependency="core" as="core"/>
|
||||
|
||||
<div rt-scope="core.translate as tr">
|
||||
<span>{tr('ANIMATION_PANEL_HEADER_LABEL'}</span>
|
||||
</div>
|
3
test/data/invalid-style.rt
Normal file
3
test/data/invalid-style.rt
Normal file
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<div style="color: {'blu}" />
|
||||
</div>
|
128
test/src/test.js
128
test/src/test.js
@ -6,7 +6,7 @@ var _ = require('lodash');
|
||||
var path = require('path');
|
||||
var React = require('react/addons');
|
||||
var cheerio = require('cheerio');
|
||||
|
||||
var RTCodeError = reactTemplates.RTCodeError;
|
||||
var dataPath = path.resolve(__dirname, '..', 'data');
|
||||
|
||||
/**
|
||||
@ -17,35 +17,23 @@ function readFileNormalized(filename) {
|
||||
return fs.readFileSync(filename).toString().replace(/\r/g, '').trim();
|
||||
}
|
||||
|
||||
test('invalid tests', function (t) {
|
||||
var files = [
|
||||
{file: 'invalid-scope.rt', issue: new reactTemplates.RTCodeError("invalid scope part 'a in a in a'", -1, -1)},
|
||||
{file: 'invalid-html.rt', issue: new reactTemplates.RTCodeError('Document should have a root element', -1, -1)},
|
||||
{file: 'invalid-exp.rt', issue: new reactTemplates.RTCodeError("Failed to parse text '\n {z\n'", 5, -1)},
|
||||
{
|
||||
file: 'invalid-lambda.rt',
|
||||
issue: new reactTemplates.RTCodeError("when using 'on' events, use lambda '(p1,p2)=>body' notation or use {} to return a callback function. error: [onClick='']", -1, -1)
|
||||
},
|
||||
{
|
||||
file: 'invalid-js.rt',
|
||||
issue: new reactTemplates.RTCodeError('Line 7: Unexpected token ILLEGAL', 187, undefined)
|
||||
},
|
||||
{
|
||||
file: 'invalid-single-root.rt',
|
||||
issue: new reactTemplates.RTCodeError('Document should have no more than a single root element', 12, 1)
|
||||
},
|
||||
{
|
||||
file: 'invalid-repeat.rt',
|
||||
issue: new reactTemplates.RTCodeError('rt-repeat invalid \'in\' expression \'a in b in c\'', -1, -1)
|
||||
},
|
||||
{
|
||||
file: 'invalid-rt-require.rt',
|
||||
issue: new reactTemplates.RTCodeError("rt-require needs 'dependency' and 'as' attributes", -1, -1)
|
||||
}
|
||||
];
|
||||
t.plan(files.length);
|
||||
var invalidFiles = [
|
||||
{file: 'invalid-scope.rt', issue: new RTCodeError("invalid scope part 'a in a in a'", 0, 35, 1, 1)},
|
||||
{file: 'invalid-html.rt', issue: new RTCodeError('Document should have a root element', -1, -1, -1, -1)},
|
||||
{file: 'invalid-exp.rt', issue: new RTCodeError("Failed to parse text '\n {z\n'", 5, 13, 1, 6)},
|
||||
{file: 'invalid-lambda.rt', issue: new RTCodeError("when using 'on' events, use lambda '(p1,p2)=>body' notation or use {} to return a callback function. error: [onClick='']", 0, 23, 1, 1)},
|
||||
{file: 'invalid-js.rt', issue: new RTCodeError('Unexpected token ILLEGAL', 0, 32, 1, 1)},
|
||||
{file: 'invalid-single-root.rt', issue: new RTCodeError('Document should have no more than a single root element', 12, 23, 2, 1)},
|
||||
{file: 'invalid-repeat.rt', issue: new RTCodeError('rt-repeat invalid \'in\' expression \'a in b in c\'', 0, 35, 1, 1)},
|
||||
{file: 'invalid-rt-require.rt', issue: new RTCodeError("rt-require needs 'dependency' and 'as' attributes", 0, 14, 1, 1)},
|
||||
{file: 'invalid-brace.rt', issue: new RTCodeError('Unexpected end of input', 128, 163, 5, 11)},
|
||||
{file: 'invalid-style.rt', issue: new RTCodeError('Unexpected token ILLEGAL', 10, 39, 2, 5)}
|
||||
];
|
||||
|
||||
files.forEach(check);
|
||||
test('invalid tests', function (t) {
|
||||
t.plan(invalidFiles.length);
|
||||
|
||||
invalidFiles.forEach(check);
|
||||
|
||||
function check(testFile) {
|
||||
var filename = path.join(dataPath, testFile.file);
|
||||
@ -56,10 +44,14 @@ test('invalid tests', function (t) {
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
t.deepEqual(errorEqual(error), errorEqual(testFile.issue), 'Expect convertTemplateToReact to throw an error');
|
||||
t.deepEqual(omitStack(error), omitStack(testFile.issue), 'Expect convertTemplateToReact to throw an error');
|
||||
}
|
||||
});
|
||||
|
||||
function omitStack(err) {
|
||||
return _.omit(err, 'stack', 'toIssue');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ERR} err
|
||||
* @return {ERR}
|
||||
@ -72,19 +64,9 @@ function normalizeError(err) {
|
||||
test('invalid tests json', function (t) {
|
||||
var cli = require('../../src/cli');
|
||||
var context = require('../../src/context');
|
||||
var files = [
|
||||
{file: 'invalid-scope.rt', issue: new reactTemplates.RTCodeError("invalid scope part 'a in a in a'", -1, -1)},
|
||||
{file: 'invalid-html.rt', issue: new reactTemplates.RTCodeError('Document should have a root element', -1, -1)},
|
||||
{file: 'invalid-exp.rt', issue: new reactTemplates.RTCodeError("Failed to parse text '\n {z\n'", 5, -1)},
|
||||
{
|
||||
file: 'invalid-lambda.rt',
|
||||
issue: new reactTemplates.RTCodeError("when using 'on' events, use lambda '(p1,p2)=>body' notation or use {} to return a callback function. error: [onClick='']", -1, -1)
|
||||
},
|
||||
{file: 'invalid-js.rt', issue: new reactTemplates.RTCodeError('Line 7: Unexpected token ILLEGAL', 187, -1)}
|
||||
];
|
||||
t.plan(files.length);
|
||||
t.plan(invalidFiles.length);
|
||||
|
||||
files.forEach(check);
|
||||
invalidFiles.forEach(check);
|
||||
|
||||
function check(testFile) {
|
||||
context.clear();
|
||||
@ -108,26 +90,15 @@ function errorEqualMessage(err, file) {
|
||||
return {
|
||||
index: err.index,
|
||||
line: err.line,
|
||||
column: err.column || -1,
|
||||
column: err.column,
|
||||
startOffset: err.startOffset,
|
||||
endOffset: err.endOffset,
|
||||
msg: err.message,
|
||||
level: 'ERROR',
|
||||
file: file
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {RTCodeError} err
|
||||
* @return {{index: number, line: number, message: string, name: string}}
|
||||
*/
|
||||
function errorEqual(err) {
|
||||
return {
|
||||
index: err.index,
|
||||
line: err.line,
|
||||
message: err.message,
|
||||
name: err.name
|
||||
};
|
||||
}
|
||||
|
||||
test('conversion test', function (t) {
|
||||
var files = ['div.rt', 'test.rt', 'repeat.rt', 'inputs.rt', 'require.rt'];
|
||||
t.plan(files.length);
|
||||
@ -218,8 +189,6 @@ test('html tests', function (t) {
|
||||
});
|
||||
|
||||
test('test context', function (t) {
|
||||
t.plan(3);
|
||||
|
||||
var context = require('../../src/context');
|
||||
context.clear();
|
||||
t.equal(context.hasErrors(), false);
|
||||
@ -227,39 +196,65 @@ test('test context', function (t) {
|
||||
t.equal(context.hasErrors(), true);
|
||||
context.clear();
|
||||
t.equal(context.hasErrors(), false);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('test shell', function (t) {
|
||||
t.plan(3);
|
||||
|
||||
var shell = require('../../src/shell');
|
||||
var context = require('../../src/context');
|
||||
var newContext = _.cloneDeep(context);
|
||||
var output;
|
||||
var outputJSON;
|
||||
newContext.options.format = 'json';
|
||||
newContext.report = function (text) {
|
||||
output = text;
|
||||
outputJSON = text;
|
||||
};
|
||||
var r = shell.printResults(newContext);
|
||||
t.equal(r, 0);
|
||||
context.error('hi', '', 1, 1);
|
||||
r = shell.printResults(newContext);
|
||||
t.equal(r, 1);
|
||||
t.equal(output, '[\n {\n "level": "ERROR",\n "msg": "hi",\n "file": null,\n "line": 1,\n "column": 1,\n "index": -1\n }\n]');
|
||||
var output = JSON.parse(outputJSON);
|
||||
t.deepEqual(output, [{column: 1, endOffset: -1, file: null, index: -1, level: 'ERROR', line: 1, msg: 'hi', startOffset: -1}]);
|
||||
context.clear();
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('test shell', function (t) {
|
||||
t.plan(1);
|
||||
|
||||
var filename = path.join(dataPath, 'div.rt');
|
||||
var cli = require('../../src/cli');
|
||||
var r = cli.execute(filename + ' -r --dry-run');
|
||||
t.equal(r, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('test convertText', function (t) {
|
||||
var texts = [
|
||||
{input: '{}', expected: '()'},
|
||||
{input: "a {'b'}", expected: '"a "+(\'b\')'}
|
||||
];
|
||||
t.plan(texts.length);
|
||||
texts.forEach(check);
|
||||
function check(testData) {
|
||||
var r = reactTemplates._test.convertText({}, {}, testData.input);
|
||||
t.equal(r, testData.expected);
|
||||
}
|
||||
});
|
||||
|
||||
test('test convertText errors', function (t) {
|
||||
var texts = [
|
||||
{input: '{}', expected: '()'},
|
||||
{input: "a {'b'}", expected: '"a "+(\'b\')'}
|
||||
];
|
||||
t.plan(texts.length);
|
||||
texts.forEach(check);
|
||||
function check(testData) {
|
||||
var r = reactTemplates._test.convertText({}, {}, testData.input);
|
||||
t.equal(r, testData.expected);
|
||||
}
|
||||
});
|
||||
|
||||
test('util.isStale', function (t) {
|
||||
t.plan(2);
|
||||
var a = path.join(dataPath, 'a.tmp');
|
||||
var b = path.join(dataPath, 'b.tmp');
|
||||
|
||||
@ -280,4 +275,5 @@ test('util.isStale', function (t) {
|
||||
|
||||
fs.unlinkSync(a);
|
||||
fs.unlinkSync(b);
|
||||
t.end();
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user