1
0
mirror of https://github.com/bobwen-dev/react-templates synced 2025-04-12 00:56:39 +02:00

added rt-include, not in playground as the only interesting use case for playground is with url support and that requires changing the entire code to be async

This commit is contained in:
Avi Marcus 2016-02-04 16:21:34 +02:00
parent 63ef4541ae
commit 9d38cbb828
6 changed files with 74 additions and 34 deletions

View File

@ -41,6 +41,7 @@ function convertFile(source, target, options, context) {
if (shouldAddName) {
options.name = reactTemplates.normalizeName(path.basename(source, path.extname(source))) + 'RT';
}
options.readFileSync = fsUtil.createRelativeReadFileSync(source);
var js = options.modules === 'jsrt' ? convertJSRTToJS(html, context, options) : convertRT(html, context, options);
if (!options.dryRun) {
fs.writeFileSync(target, js);

View File

@ -1,5 +1,6 @@
'use strict';
var fs = require('fs');
var path = require('path');
/**
* @param {string} source
@ -15,6 +16,14 @@ function isStale(source, target) {
return sourceTime.getTime() > targetTime.getTime();
}
function createRelativeReadFileSync(baseFile) {
var basePath = path.dirname(baseFile);
return function(filename) {
return fs.readFileSync(path.resolve(basePath, filename));
}
}
module.exports = {
isStale: isStale
};
isStale: isStale,
createRelativeReadFileSync: createRelativeReadFileSync
};

View File

@ -52,6 +52,8 @@ var scopeAttr = 'rt-scope';
var propsAttr = 'rt-props';
var templateNode = 'rt-template';
var virtualNode = 'rt-virtual';
var includeNode = 'rt-include';
var includeSrcAttr = 'src';
/**
* @param {Options} options
@ -304,12 +306,17 @@ function convertTagNameToConstructor(tagName, context) {
* @param options
* @return {Context}
*/
function defaultContext(html, options) {
function defaultContext(html, options, reportContext) {
var defaultDefines = {};
defaultDefines[options.reactImportPath] = 'React';
defaultDefines[options.lodashImportPath] = '_';
return {
boundParams: [],
injectedFunctions: [],
html: html,
options: options
options: options,
defines: options.defines ? _.clone(options.defines) : defaultDefines,
reportContext: reportContext
};
}
@ -328,12 +335,27 @@ function hasNonSimpleChildren(node) {
*/
function convertHtmlToReact(node, context) {
if (node.type === 'tag' || node.type === 'style') {
context = {
boundParams: _.clone(context.boundParams),
injectedFunctions: context.injectedFunctions,
html: context.html,
options: context.options
};
context = _.defaults({
boundParams: _.clone(context.boundParams)
}, context);
if (node.type === 'tag' && node.name === includeNode) {
var srcFile = node.attribs[includeSrcAttr];
if (!srcFile) {
throw RTCodeError.build(context, node, 'rt-include must supply a source attribute');
}
if (!context.options.readFileSync) {
throw RTCodeError.build(context, node, 'rt-include needs a readFileSync polyfill on options');
}
try {
var newHtml = context.options.readFileSync(srcFile);
} catch (e) {
console.error(e);
throw RTCodeError.build(context, node, `rt-include failed to read file '${srcFile}'`);
}
context.html = newHtml;
return parseAndConvertHtmlToReact(newHtml, context);
}
var data = {name: convertTagNameToConstructor(node.name, context)};
@ -490,24 +512,9 @@ function convertTemplateToReact(html, options) {
return convertRT(html, context, options);
}
/**
* @param {string} html
* @param {CONTEXT} reportContext
* @param {Options?} options
* @return {string}
*/
function convertRT(html, reportContext, options) {
function parseAndConvertHtmlToReact(html, context) {
var rootNode = cheerio.load(html, {lowerCaseTags: false, lowerCaseAttributeNames: false, xmlMode: true, withStartIndices: true});
options = getOptions(options);
var defaultDefines = {};
defaultDefines[options.reactImportPath] = 'React';
defaultDefines[options.lodashImportPath] = '_';
var defines = options.defines ? _.clone(options.defines) : defaultDefines;
var context = defaultContext(html, options);
utils.validate(options, context, reportContext, rootNode.root()[0]);
utils.validate(context.options, context, context.reportContext, rootNode.root()[0]);
var rootTags = _.filter(rootNode.root()[0].children, isTag);
rootTags = handleSelfClosingHtmlTags(rootTags);
if (!rootTags || rootTags.length === 0) {
@ -521,7 +528,7 @@ function convertRT(html, reportContext, options) {
} else if (tag.children.length) {
throw RTCodeError.build(context, tag, 'rt-require may have no children');
}
defines[tag.attribs.dependency] = tag.attribs.as;
context.defines[tag.attribs.dependency] = tag.attribs.as;
} else if (firstTag === null) {
firstTag = tag;
} else {
@ -533,8 +540,22 @@ function convertRT(html, reportContext, options) {
} else if (firstTag.name === virtualNode) {
throw RTCodeError.build(context, firstTag, `Document should not have <${virtualNode}> as root element`);
}
var body = convertHtmlToReact(firstTag, context);
var requirePaths = _(defines)
return convertHtmlToReact(firstTag, context);
}
/**
* @param {string} html
* @param {CONTEXT} reportContext
* @param {Options?} options
* @return {string}
*/
function convertRT(html, reportContext, options) {
options = getOptions(options);
var context = defaultContext(html, options, reportContext);
var body = parseAndConvertHtmlToReact(html, context);
var requirePaths = _(context.defines)
.keys()
.map(def => `"${def}"`)
.join(',');
@ -547,8 +568,8 @@ function convertRT(html, reportContext, options) {
buildImport = (v, p) => `var ${v} = require('${p}');`
}
const header = options.flow ? '/* @flow */\n' : '';
const vars = header + _(defines).map(buildImport).join('\n');
var data = {body, injectedFunctions: context.injectedFunctions.join('\n'), requireNames: _.values(defines).join(','), requirePaths, vars, name: options.name};
const vars = header + _(context.defines).map(buildImport).join('\n');
var data = {body, injectedFunctions: context.injectedFunctions.join('\n'), requireNames: _.values(context.defines).join(','), requirePaths, vars, name: options.name};
var code = generate(data, options);
if (options.modules !== 'typescript' && options.modules !== 'jsrt') {
code = parseJS(code);

3
test/data/include.rt Normal file
View File

@ -0,0 +1,3 @@
<div>
<rt-include src="className.rt"/>
</div>

View File

@ -0,0 +1 @@
<div><div class="a"></div></div>

View File

@ -3,6 +3,7 @@ var test = require('tape');
var reactTemplates = require('../../src/reactTemplates');
var context = require('../../src/context');
var util = require('./util');
var fsUtil = require('../../src/fsUtil');
var readFileNormalized = util.readFileNormalized;
var compareAndWrite = util.compareAndWrite;
var fs = require('fs');
@ -203,7 +204,8 @@ test('html tests', function (t) {
"scope-evaluated-after-repeat2.rt",
"scope-evaluated-after-if.rt",
"scope-obj.rt",
"repeat-literal-collection.rt"
"repeat-literal-collection.rt",
"include.rt"
];
t.plan(files.length);
@ -211,12 +213,15 @@ test('html tests', function (t) {
function check(testFile) {
var filename = path.join(dataPath, testFile);
var options = {
readFileSync: fsUtil.createRelativeReadFileSync(filename)
}
var code = '';
try {
var html = fs.readFileSync(filename).toString();
var expected = readFileNormalized(filename + '.html');
// var expected = fs.readFileSync(filename.replace(".html", ".js")).toString();
code = reactTemplates.convertTemplateToReact(html).replace(/\r/g, '');
code = reactTemplates.convertTemplateToReact(html, options).replace(/\r/g, '');
var actual = util.codeToHtml(code);
actual = util.normalizeHtml(actual);
expected = util.normalizeHtml(expected);