mirror of
https://github.com/bobwen-dev/react-templates
synced 2025-04-12 00:56:39 +02:00
New syntax for rt-require: "import" "from" (#125)
* New syntaxt for rt-require import="" from="" * Added warning message for obsolete syntax * Allow to import multiple names from the same module * Added tests for rt-require new import syntax * Removed unneded comment * Separated rt-require into rt-require and rt-import * Tests for rt-require and rt-import
This commit is contained in:
parent
b2483bd2de
commit
c495a02452
@ -55,10 +55,49 @@ const templates = {
|
||||
jsrt: templateJSRTTemplate
|
||||
};
|
||||
|
||||
function buildImportTypeScript(d) { /* eslint-disable no-else-return */
|
||||
if (d.member === '*') {
|
||||
return `import ${d.alias} = require('${d.moduleName}');`;
|
||||
} else {
|
||||
return `import ${d.alias} = require('${d.moduleName}').${d.member};`;
|
||||
}
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
function buildImportES6(d) { /* eslint-disable no-else-return */
|
||||
if (d.member === '*') {
|
||||
return `import * as ${d.alias} from '${d.moduleName}';`;
|
||||
} else if (d.member === 'default') {
|
||||
return `import ${d.alias} from '${d.moduleName}';`;
|
||||
} else {
|
||||
return `import { ${d.member} as ${d.alias} } from '${d.moduleName}';`;
|
||||
}
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
function buildImportCommonJS(d) { /* eslint-disable no-else-return */
|
||||
if (d.member === '*') {
|
||||
return `var ${d.alias} = require('${d.moduleName}');`;
|
||||
} else {
|
||||
return `var ${d.alias} = require('${d.moduleName}').${d.member};`;
|
||||
}
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
const buildImport = {
|
||||
typescript: buildImportTypeScript,
|
||||
es6: buildImportES6,
|
||||
commonjs: buildImportCommonJS,
|
||||
amd: buildImportCommonJS,
|
||||
none: buildImportCommonJS,
|
||||
jsrt: buildImportCommonJS
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
htmlSelfClosingTags,
|
||||
attributesMapping,
|
||||
classNameProp,
|
||||
shouldUseCreateElement,
|
||||
templates
|
||||
templates,
|
||||
buildImport
|
||||
};
|
||||
|
@ -53,6 +53,8 @@ const templateNode = 'rt-template';
|
||||
const virtualNode = 'rt-virtual';
|
||||
const includeNode = 'rt-include';
|
||||
const includeSrcAttr = 'src';
|
||||
const requireAttr = 'rt-require';
|
||||
const importAttr = 'rt-import';
|
||||
|
||||
const reactTemplatesSelfClosingTags = [includeNode];
|
||||
|
||||
@ -256,9 +258,10 @@ function convertTagNameToConstructor(tagName, context) {
|
||||
* @return {Context}
|
||||
*/
|
||||
function defaultContext(html, options, reportContext) {
|
||||
const defaultDefines = {};
|
||||
defaultDefines[options.reactImportPath] = 'React';
|
||||
defaultDefines[options.lodashImportPath] = '_';
|
||||
const defaultDefines = [
|
||||
{moduleName: options.reactImportPath, alias: 'React', member: '*'},
|
||||
{moduleName: options.lodashImportPath, alias: '_', member: '*'}
|
||||
];
|
||||
return {
|
||||
boundParams: [],
|
||||
injectedFunctions: [],
|
||||
@ -464,6 +467,48 @@ function handleSelfClosingHtmlTags(nodes) {
|
||||
});
|
||||
}
|
||||
|
||||
function handleRequire(tag, context) {
|
||||
let moduleName;
|
||||
let alias;
|
||||
let member;
|
||||
if (tag.children.length) {
|
||||
throw RTCodeError.build(context, tag, `'${requireAttr}' may have no children`);
|
||||
} else if (tag.attribs.dependency && tag.attribs.as) {
|
||||
moduleName = tag.attribs.dependency;
|
||||
member = '*';
|
||||
alias = tag.attribs.as;
|
||||
}
|
||||
if (!moduleName) {
|
||||
throw RTCodeError.build(context, tag, `'${requireAttr}' needs 'dependency' and 'as' attributes`);
|
||||
}
|
||||
context.defines.push({moduleName, member, alias});
|
||||
}
|
||||
|
||||
function handleImport(tag, context) {
|
||||
let moduleName;
|
||||
let alias;
|
||||
let member;
|
||||
if (tag.children.length) {
|
||||
throw RTCodeError.build(context, tag, `'${importAttr}' may have no children`);
|
||||
} else if (tag.attribs.name && tag.attribs.from) {
|
||||
moduleName = tag.attribs.from;
|
||||
member = tag.attribs.name;
|
||||
alias = tag.attribs.as;
|
||||
if (!alias) {
|
||||
if (member === '*') {
|
||||
throw RTCodeError.build(context, tag, "'*' imports must have an 'as' attribute");
|
||||
} else if (member === 'default') {
|
||||
throw RTCodeError.build(context, tag, "default imports must have an 'as' attribute");
|
||||
}
|
||||
alias = member;
|
||||
}
|
||||
}
|
||||
if (!moduleName) {
|
||||
throw RTCodeError.build(context, tag, `'${importAttr}' needs 'name' and 'from' attributes`);
|
||||
}
|
||||
context.defines.push({moduleName, member, alias});
|
||||
}
|
||||
|
||||
function convertTemplateToReact(html, options) {
|
||||
const context = require('./context');
|
||||
return convertRT(html, context, options);
|
||||
@ -484,13 +529,10 @@ function parseAndConvertHtmlToReact(html, context) {
|
||||
}
|
||||
let firstTag = null;
|
||||
_.forEach(rootTags, tag => {
|
||||
if (tag.name === 'rt-require') {
|
||||
if (!tag.attribs.dependency || !tag.attribs.as) {
|
||||
throw RTCodeError.build(context, tag, "rt-require needs 'dependency' and 'as' attributes");
|
||||
} else if (tag.children.length) {
|
||||
throw RTCodeError.build(context, tag, 'rt-require may have no children');
|
||||
}
|
||||
context.defines[tag.attribs.dependency] = tag.attribs.as;
|
||||
if (tag.name === requireAttr) {
|
||||
handleRequire(tag, context);
|
||||
} else if (tag.name === importAttr) {
|
||||
handleImport(tag, context);
|
||||
} else if (firstTag === null) {
|
||||
firstTag = tag;
|
||||
} else {
|
||||
@ -517,24 +559,16 @@ function convertRT(html, reportContext, options) {
|
||||
const context = defaultContext(html, options, reportContext);
|
||||
const body = parseAndConvertHtmlToReact(html, context);
|
||||
|
||||
const requirePaths = _(context.defines)
|
||||
.keys()
|
||||
.map(def => `"${def}"`)
|
||||
.join(',');
|
||||
let buildImport;
|
||||
if (options.modules === 'typescript') {
|
||||
buildImport = (v, p) => `import ${v} = require('${p}');`;
|
||||
} else if (options.modules === 'es6') { // eslint-disable-line
|
||||
buildImport = (v, p) => `import ${v} from '${p}';`;
|
||||
} else {
|
||||
buildImport = (v, p) => `var ${v} = require('${p}');`;
|
||||
}
|
||||
const requirePaths = _.map(context.defines, d => `"${d.moduleName}"`).join(',');
|
||||
const requireNames = _.map(context.defines, d => `${d.alias}`).join(',');
|
||||
const buildImport = reactSupport.buildImport[options.modules] || reactSupport.buildImport.commonjs;
|
||||
const requires = _.map(context.defines, buildImport).join('\n');
|
||||
const header = options.flow ? '/* @flow */\n' : '';
|
||||
const vars = header + _(context.defines).map(buildImport).join('\n');
|
||||
const vars = header + requires;
|
||||
const data = {
|
||||
body,
|
||||
injectedFunctions: context.injectedFunctions.join('\n'),
|
||||
requireNames: _.values(context.defines).join(','),
|
||||
requireNames,
|
||||
requirePaths,
|
||||
vars,
|
||||
name: options.name
|
||||
|
@ -72,6 +72,10 @@ function validate(options, context, reportContext, node) {
|
||||
const loc = rtError.getNodeLoc(context, node);
|
||||
reportContext.warn('rt-if without a key', options.fileName, loc.pos.line, loc.pos.col, loc.start, loc.end);
|
||||
}
|
||||
if (node.type === 'tag' && node.attribs['rt-require'] && (node.attribs.dependency || node.attribs.as)) {
|
||||
const loc = rtError.getNodeLoc(context, node);
|
||||
reportContext.warn("'rt-require' is obsolete, use 'rt-import' instead", options.fileName, loc.pos.line, loc.pos.col, loc.start, loc.end);
|
||||
}
|
||||
if (node.children) {
|
||||
node.children.forEach(validate.bind(this, options, context, reportContext));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react/addons';
|
||||
import _ from 'lodash';
|
||||
import * as React from 'react/addons';
|
||||
import * as _ from 'lodash';
|
||||
export default function () {
|
||||
return React.createElement('div', {});
|
||||
}
|
6
test/data/import.rt
Normal file
6
test/data/import.rt
Normal file
@ -0,0 +1,6 @@
|
||||
<rt-import name="member" from="module-name"/>
|
||||
<rt-import name="member" as="alias2" from="module-name"/>
|
||||
<rt-import name="*" as="alias3" from="module-name"/>
|
||||
<rt-import name="default" as="alias4" from="module-name"/>
|
||||
<div>
|
||||
</div>
|
13
test/data/import.rt.amd.js
Normal file
13
test/data/import.rt.amd.js
Normal file
@ -0,0 +1,13 @@
|
||||
define('div', [
|
||||
'react/addons',
|
||||
'lodash',
|
||||
'module-name',
|
||||
'module-name',
|
||||
'module-name',
|
||||
'module-name'
|
||||
], function (React, _, member, alias2, alias3, alias4) {
|
||||
'use strict';
|
||||
return function () {
|
||||
return React.createElement('div', {});
|
||||
};
|
||||
});
|
10
test/data/import.rt.commonjs.js
Normal file
10
test/data/import.rt.commonjs.js
Normal file
@ -0,0 +1,10 @@
|
||||
'use strict';
|
||||
var React = require('react/addons');
|
||||
var _ = require('lodash');
|
||||
var member = require('module-name').member;
|
||||
var alias2 = require('module-name').member;
|
||||
var alias3 = require('module-name');
|
||||
var alias4 = require('module-name').default;
|
||||
module.exports = function () {
|
||||
return React.createElement('div', {});
|
||||
};
|
9
test/data/import.rt.es6.js
Normal file
9
test/data/import.rt.es6.js
Normal file
@ -0,0 +1,9 @@
|
||||
import * as React from 'react/addons';
|
||||
import * as _ from 'lodash';
|
||||
import { member } from 'module-name';
|
||||
import { member as alias2 } from 'module-name';
|
||||
import * as alias3 from 'module-name';
|
||||
import alias4 from 'module-name';
|
||||
export default function () {
|
||||
return React.createElement('div', {});
|
||||
}
|
3
test/data/import.rt.globals.js
Normal file
3
test/data/import.rt.globals.js
Normal file
@ -0,0 +1,3 @@
|
||||
var div = function () {
|
||||
return React.createElement('div', {});
|
||||
};
|
11
test/data/import.rt.js
Normal file
11
test/data/import.rt.js
Normal file
@ -0,0 +1,11 @@
|
||||
define([
|
||||
'react/addons',
|
||||
'lodash',
|
||||
'comps/myComp',
|
||||
'utils/utils'
|
||||
], function (React, _, myComp, utils) {
|
||||
'use strict';
|
||||
return function () {
|
||||
return React.createElement(myComp, {}, '\n', utils.translate('Hello', 'es'), '\n');
|
||||
};
|
||||
});
|
10
test/data/import.rt.typescript.ts
Normal file
10
test/data/import.rt.typescript.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import React = require('react/addons');
|
||||
import _ = require('lodash');
|
||||
import member = require('module-name').member;
|
||||
import alias2 = require('module-name').member;
|
||||
import alias3 = require('module-name');
|
||||
import alias4 = require('module-name').default;
|
||||
|
||||
|
||||
var fn = function() { return React.createElement('div',{}) };
|
||||
export = fn
|
3
test/data/invalid/invalid-rt-import-1.rt
Normal file
3
test/data/invalid/invalid-rt-import-1.rt
Normal file
@ -0,0 +1,3 @@
|
||||
<rt-import name="*" from="module" />
|
||||
<div>
|
||||
</div>
|
3
test/data/invalid/invalid-rt-import-2.rt
Normal file
3
test/data/invalid/invalid-rt-import-2.rt
Normal file
@ -0,0 +1,3 @@
|
||||
<rt-import name="default" from="module" />
|
||||
<div>
|
||||
</div>
|
3
test/data/invalid/invalid-rt-import-3.rt
Normal file
3
test/data/invalid/invalid-rt-import-3.rt
Normal file
@ -0,0 +1,3 @@
|
||||
<rt-import />
|
||||
<div>
|
||||
</div>
|
5
test/data/invalid/invalid-rt-require-2.rt
Normal file
5
test/data/invalid/invalid-rt-require-2.rt
Normal file
@ -0,0 +1,5 @@
|
||||
<rt-require>
|
||||
42
|
||||
</rt-require>
|
||||
<div>
|
||||
</div>
|
11
test/data/require.rt.amd.js
Normal file
11
test/data/require.rt.amd.js
Normal file
@ -0,0 +1,11 @@
|
||||
define('div', [
|
||||
'react/addons',
|
||||
'lodash',
|
||||
'comps/myComp',
|
||||
'utils/utils'
|
||||
], function (React, _, myComp, utils) {
|
||||
'use strict';
|
||||
return function () {
|
||||
return React.createElement(myComp, {}, '\n', utils.translate('Hello', 'es'), '\n');
|
||||
};
|
||||
});
|
8
test/data/require.rt.commonjs.js
Normal file
8
test/data/require.rt.commonjs.js
Normal file
@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
var React = require('react/addons');
|
||||
var _ = require('lodash');
|
||||
var myComp = require('comps/myComp');
|
||||
var utils = require('utils/utils');
|
||||
module.exports = function () {
|
||||
return React.createElement(myComp, {}, '\n', utils.translate('Hello', 'es'), '\n');
|
||||
};
|
7
test/data/require.rt.es6.js
Normal file
7
test/data/require.rt.es6.js
Normal file
@ -0,0 +1,7 @@
|
||||
import * as React from 'react/addons';
|
||||
import * as _ from 'lodash';
|
||||
import * as myComp from 'comps/myComp';
|
||||
import * as utils from 'utils/utils';
|
||||
export default function () {
|
||||
return React.createElement(myComp, {}, '\n', utils.translate('Hello', 'es'), '\n');
|
||||
}
|
3
test/data/require.rt.globals.js
Normal file
3
test/data/require.rt.globals.js
Normal file
@ -0,0 +1,3 @@
|
||||
var div = function () {
|
||||
return React.createElement(myComp, {}, '\n', utils.translate('Hello', 'es'), '\n');
|
||||
};
|
8
test/data/require.rt.typescript.ts
Normal file
8
test/data/require.rt.typescript.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import React = require('react/addons');
|
||||
import _ = require('lodash');
|
||||
import myComp = require('comps/myComp');
|
||||
import utils = require('utils/utils');
|
||||
|
||||
|
||||
var fn = function() { return React.createElement(myComp,{},"\n",(utils.translate('Hello','es')),"\n") };
|
||||
export = fn
|
@ -23,7 +23,11 @@ module.exports = {
|
||||
{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-rt-require-1.rt', issue: new RTCodeError("'rt-require' needs 'dependency' and 'as' attributes", 0, 14, 1, 1)},
|
||||
{file: 'invalid-rt-require-2.rt', issue: new RTCodeError("'rt-require' may have no children", 0, 32, 1, 1)},
|
||||
{file: 'invalid-rt-import-1.rt', issue: new RTCodeError("'*' imports must have an 'as' attribute", 0, 36, 1, 1)},
|
||||
{file: 'invalid-rt-import-2.rt', issue: new RTCodeError("default imports must have an 'as' attribute", 0, 42, 1, 1)},
|
||||
{file: 'invalid-rt-import-3.rt', issue: new RTCodeError("'rt-import' needs 'name' and 'from' attributes", 0, 13, 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)},
|
||||
{file: 'invalid-virtual.rt', issue: new RTCodeError('Document should not have <rt-virtual> as root element', 0, 60, 1, 1)}
|
||||
|
@ -29,7 +29,7 @@ module.exports = {
|
||||
});
|
||||
|
||||
test('conversion test', t => {
|
||||
const files = ['div.rt', 'test.rt', 'repeat.rt', 'inputs.rt', 'require.rt', 'virtual.rt'];
|
||||
const files = ['div.rt', 'test.rt', 'repeat.rt', 'inputs.rt', 'virtual.rt'];
|
||||
testFiles(t, files);
|
||||
});
|
||||
|
||||
@ -63,7 +63,7 @@ module.exports = {
|
||||
{source: 'div.rt', expected: 'div.rt.commonjs.js', options: {modules: 'commonjs'}},
|
||||
{source: 'div.rt', expected: 'div.rt.amd.js', options: {modules: 'amd', name: 'div'}},
|
||||
{source: 'div.rt', expected: 'div.rt.globals.js', options: {modules: 'none', name: 'div'}},
|
||||
{source: 'div.rt', expected: 'div.rt.es6.js', options: {modules: 'es6', name: 'div'}},
|
||||
{source: 'div.rt', expected: 'div.rt.es6.js', options: {modules: 'es6'}},
|
||||
{source: 'div.rt', expected: 'div.rt.typescript.ts', options: {modules: 'typescript'}}
|
||||
];
|
||||
t.plan(files.length);
|
||||
@ -78,6 +78,46 @@ module.exports = {
|
||||
}
|
||||
});
|
||||
|
||||
test('rt-require with all module types', t => {
|
||||
const files = [
|
||||
{source: 'require.rt', expected: 'require.rt.commonjs.js', options: {modules: 'commonjs'}},
|
||||
{source: 'require.rt', expected: 'require.rt.amd.js', options: {modules: 'amd', name: 'div'}},
|
||||
{source: 'require.rt', expected: 'require.rt.globals.js', options: {modules: 'none', name: 'div'}},
|
||||
{source: 'require.rt', expected: 'require.rt.es6.js', options: {modules: 'es6'}},
|
||||
{source: 'require.rt', expected: 'require.rt.typescript.ts', options: {modules: 'typescript'}}
|
||||
];
|
||||
t.plan(files.length);
|
||||
files.forEach(check);
|
||||
|
||||
function check(testData) {
|
||||
const filename = path.join(dataPath, testData.source);
|
||||
const html = readFileNormalized(filename);
|
||||
const expected = readFileNormalized(path.join(dataPath, testData.expected));
|
||||
const actual = reactTemplates.convertTemplateToReact(html, testData.options).replace(/\r/g, '').trim();
|
||||
compareAndWrite(t, actual, expected, filename);
|
||||
}
|
||||
});
|
||||
|
||||
test('rt-import with all module types', t => {
|
||||
const files = [
|
||||
{source: 'import.rt', expected: 'import.rt.commonjs.js', options: {modules: 'commonjs'}},
|
||||
{source: 'import.rt', expected: 'import.rt.amd.js', options: {modules: 'amd', name: 'div'}},
|
||||
{source: 'import.rt', expected: 'import.rt.globals.js', options: {modules: 'none', name: 'div'}},
|
||||
{source: 'import.rt', expected: 'import.rt.es6.js', options: {modules: 'es6'}},
|
||||
{source: 'import.rt', expected: 'import.rt.typescript.ts', options: {modules: 'typescript'}}
|
||||
];
|
||||
t.plan(files.length);
|
||||
files.forEach(check);
|
||||
|
||||
function check(testData) {
|
||||
const filename = path.join(dataPath, testData.source);
|
||||
const html = readFileNormalized(filename);
|
||||
const expected = readFileNormalized(path.join(dataPath, testData.expected));
|
||||
const actual = reactTemplates.convertTemplateToReact(html, testData.options).replace(/\r/g, '').trim();
|
||||
compareAndWrite(t, actual, expected, filename);
|
||||
}
|
||||
});
|
||||
|
||||
test('convert jsrt and test source results', t => {
|
||||
const files = ['simple.jsrt'];
|
||||
t.plan(files.length);
|
||||
|
Loading…
x
Reference in New Issue
Block a user