Skip to content
This repository has been archived by the owner on Mar 25, 2018. It is now read-only.

Commit

Permalink
feat: add option.exportName
Browse files Browse the repository at this point in the history
  • Loading branch information
birhoff committed Feb 22, 2017
1 parent 42c817c commit 81fc86b
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 52 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ bem-xjst engines accesible via properties `bemhtml` and `bemtree`:
var engine = require('gulp-bem-xjst')[engine];
```

### Plugin options
### Options

* *String* **exportName** — Engine handler's variable name. Default — `BEMHTML`.
* *String* **engine** — Engine's name. Default — `BEMHTML`.
* *String* **exportName** — Engine handler's variable name.
* *String* **extension** — extension for file. Default — `.${engine}.js`.
* *Object* **engine** — XJST [options](https://github.com/bem/bem-xjst/blob/master/docs/en/3-api.md#settings).

### License

Expand Down
8 changes: 3 additions & 5 deletions error.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ var format = util.format;
* @param {String} filepath - Path to the file
* @return {String|Object}
*/
module.exports = function (err, code, filepath) {
module.exports = function(err, code, filepath) {
// Assume that esprima parser failed
if (err.description && err.column && err.lineNumber) {
var source = code.split('\n');
Expand All @@ -23,14 +23,12 @@ module.exports = function (err, code, filepath) {

var fragment = source.slice(startLine, endLine);
// Adding marker
fragment.splice(errorLine - startLine + 1, 0, Array(err.column).join(' ') + '^');
fragment.splice(errorLine - startLine + 1, 0, new Array(err.column).join(' ') + '^');

var message = format('%s at %s:\n%s',
return format('%s at %s:\n%s',
err.description,
path.basename(filepath),
fragment.join('\n'));

return message;
}

return err;
Expand Down
40 changes: 23 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,18 @@ var isStream = require('is-stream');
var toArray = require('stream-to-array');

var formatError = require('./error');
var bundle = require('./lib/templates/bundle');

var pluginName = path.basename(__dirname);

/**
* bem-xjst templates compiler.
*
* @param {{extension: string}} options - Options for generator.
* @param {Object} [options] - Options for generator.
* @param {String} [options.extension] - File extension. Default: engine name.
* @param {String} [options.exportName] - Name for export. Please notice if you set this option generated code will
* @param {Object} [options.engine] - Engine compiler options. @see
* https://github.com/bem/bem-xjst/blob/master/docs/en/3-api.md#settings wrapped with CommonJS, YModules or Global
* @param {String|Function} engine - 'bemhtml' either 'bemtree' or any xjst-like engine function.
* @returns {Stream}
*/
Expand All @@ -32,7 +37,7 @@ module.exports = function(options, engine) {
engineName = engine;
engine = bemxjst[engine];
} else {
engineName = (engine.engineName || engine.name || Object(engine.runtime).name).toLowerCase() || 'xjst';
engineName = (engine.engineName || (engine.runtime && engine.runtime.name)).toLowerCase() || 'xjst';
}

return through.obj(function(file, encoding, callback) {
Expand All @@ -44,16 +49,17 @@ module.exports = function(options, engine) {
return callback(new PluginError(pluginName, 'Streaming not supported'));
}

var res;
var code = file.contents.toString();
var res = tryCatch(function() {
return engine.generate(code, options);
}, function(e) {
return new PluginError(pluginName, formatError(e, code, file.path), {

try {
var compiledCode = engine.generate(code, options);
res = options.exportName ? bundle(compiledCode, options) : compiledCode;
} catch (e) {
var err = new PluginError(pluginName, formatError(e, code, file.path), {
fileName: file.path
});
});
if (res instanceof PluginError) {
return callback(res);
return callback(err);
}

file.contents = new Buffer(res);
Expand All @@ -75,8 +81,8 @@ module.exports.bemtree = function(options) {
/**
* Wrapper for anything.apply with bemjson.
*
* @param {Stream<Vinyl>} templatesStream - Stream with bemhtmls
* @returns {TransformStream<Vinyl>} - transform stream that applies templates to each incoming bemjson vinyl
* @param {Stream<File>} templatesStream - Stream with bemhtmls
* @returns {stream.Transform<File>} - transform stream that applies templates to each incoming bemjson vinyl
*/
module.exports.toHtml = function(templatesStream) {
if (!isStream(templatesStream)) {
Expand All @@ -93,9 +99,9 @@ module.exports.toHtml = function(templatesStream) {
return callback(new PluginError(pluginName, 'Streaming not supported'));
}

tryCatch(function () {
tryCatch(function() {
return bemjsonFile.data || (bemjsonFile.data = _eval(String(bemjsonFile.contents), bemjsonFile.path));
}, function (err) {
}, function(err) {
callback(new PluginError(pluginName, 'Error at evaluating bemjson: ' + err));
});

Expand All @@ -107,16 +113,16 @@ module.exports.toHtml = function(templatesStream) {
var _this = this;

templatesPromise
.then(function (templatesVinyls) {
.then(function(templatesVinyls) {
// Handle multiple templates case
var n = 0;

templatesVinyls.forEach(function(file) {
file.data || (file.data = _eval(String(file.contents)));

var html = tryCatch(function () {
var html = tryCatch(function() {
return file.data.apply(bemjsonFile.data);
}, function (err) {
}, function(err) {
throw new Error('BEMHTML error: ' + err);
});

Expand All @@ -135,7 +141,7 @@ module.exports.toHtml = function(templatesStream) {

callback();
})
.catch(function (err) {
.catch(function(err) {
callback(new PluginError(pluginName, err));
});
});
Expand Down
41 changes: 41 additions & 0 deletions lib/assets/bundle.jst
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
var ${ exportName };

(function(global) {
function buildBemXjst() {
var exports = {};

${ bemxjst }

return exports;
};

var defineAsGlobal = true;

// Provide with CommonJS
if (typeof module === 'object' && typeof module.exports === 'object') {
exports['${ exportName }'] = buildBemXjst();
defineAsGlobal = false;
}

// Provide to YModules
if (typeof modules === 'object') {
modules.define(
'${ exportName }',
[<%_.each([], function(name) {%>'${ name }',<%});%>],
function(
provide<%if ([].length) {%>,<%}%>
${ [].join(', ') }
) {
provide(buildBemXjst());
}
);

defineAsGlobal = false;
}

// Provide to global scope
if (defineAsGlobal) {
${ exportName } = buildBemXjst();
global['${ exportName }'] = ${ exportName };
}
})(typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : this);
31 changes: 31 additions & 0 deletions lib/templates/bundle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
var fs = require('fs');
var path = require('path');

var _ = require('lodash');

var assetDir = path.join(__dirname, '..', 'assets');
var templates = {
bundle: { path: path.join(assetDir, 'bundle.jst') }
};

// load templates
_.mapKeys(templates, function(template, name) {
templates[name] = _.template(fs.readFileSync(template.path, 'utf-8'));
});

/**
* Template for compile BEMHTML or BEMTREE to bundle.
*
* @param {String} code - Code compiled with the `bem-xjst` (BEMHTML or BEMTREE).
* @param {Object} options - Options.
* @param {String} [options.exportName=BEMHTML] - Name for exports.
* @returns {String}
*/
module.exports = function(code, options) {
options || (options = {});

return templates.bundle({
exportName: options.exportName || 'BEMHTML',
bemxjst: code
});
};
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
"dependencies": {
"bem-xjst": "^8.4.0",
"is-stream": "^1.1.0",
"gulp-util": "^3.0.7",
"lodash": "^4.17.4",
"node-eval": "^1.1.0",
"plugin-error": "^0.1.2",
"stream-to-array": "^2.3.0",
Expand Down
120 changes: 93 additions & 27 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,62 +1,128 @@
describe('gulp-bemhtml', function () {
describe('gulp-bemhtml', function() {
'use strict';

var lib = require('..');
var expect = require('expect.js');
var bemxjst = require('bem-xjst');
var File = require('vinyl');
var gutil = require('gulp-util');
var _eval = require('node-eval');
var intoStream = require('into-stream');

describe('stream', function () {
describe('stream', function() {
var stream;
var vinylFile;

before(function (next) {
stream = lib.bemhtml()
.on('data', function (file) {
vinylFile = file;
})
before(function(next) {
stream = lib.bemhtml();

stream.on('data', function(file) {
vinylFile = file;
})
.on('error', next)
.on('end', next);

intoStream.obj([new File({
path: 'page.bemhtml',
contents: new Buffer('block(\'page\')(tag()(\'h1\'), content()(\'Hello, world!\'));')
})])
.pipe(stream);
stream.write(new gutil.File({
path: 'page.bemhtml',
contents: new Buffer('block(\'page\')(tag()(\'h1\'), content()(\'Hello, world!\'));')
}));
stream.end();
});

it('changes file extension to *.bemhtml.js', function () {
it('changes file extension to *.bemhtml.js', function() {
expect(vinylFile.relative).to.be.equal('page.bemhtml.js');
});

it('outputs bemhtml templates compiler', function () {
it('outputs bemhtml templates compiler', function() {
var bemhtml = _eval(vinylFile.contents.toString());
expect(bemhtml.apply({block: 'page'})).to.be.equal('<h1 class="page">Hello, world!</h1>');
expect(bemhtml.apply({ block: 'page' })).to.be.equal('<h1 class="page">Hello, world!</h1>');
});
});

describe('stream with custom engine', function () {
describe('stream with custom engine', function() {
var stream;
var vinylFile;

before(function (next) {
const stream = lib({}, bemxjst.bemhtml)
.on('data', function (file) {
vinylFile = file;
})
before(function(next) {
stream = lib({}, bemxjst.bemhtml);

stream.on('data', function(file) {
vinylFile = file;
})
.on('error', next)
.on('end', next);

intoStream.obj([new File({
stream.write(new gutil.File({
path: 'page.bemhtml',
contents: new Buffer('block(\'page\')(tag()(\'h1\'), content()(\'Hello, world!\'));')
})])
.pipe(stream);
}));
stream.end();
});

it('changes file extension to *.bemhtml.js', function () {
it('changes file extension to *.bemhtml.js', function() {
expect(vinylFile.relative).to.be.equal('page.bemhtml.js');
});
});

describe('stream with exportName', function() {
var stream;
var vinylFile;

before(function(next) {
stream = lib.bemhtml({ exportName: 'BEMHTML' });

stream.on('data', function(file) {
vinylFile = file;
})
.on('error', next)
.on('end', next);

stream.write(new gutil.File({
path: 'page.bemhtml',
contents: new Buffer('block(\'page\')(tag()(\'h1\'), content()(\'Hello, world!\'));')
}));
stream.end();
});

it('should export compiler to global', function() {
var engine = _eval(vinylFile.contents.toString());

expect(engine).to.have.property('BEMHTML');
expect(engine.BEMHTML.apply).to.be.a('function');
});

it('should export compiler to custom name', function(next) {

var testStream = lib.bemhtml({ exportName: 'customProperty' });
var testFile;

testStream.on('data', function(file) { testFile = file; })
.on('error', compileDone)
.on('end', compileDone);

testStream.write(new gutil.File({
path: 'page.bemhtml',
contents: new Buffer('block(\'page\')(tag()(\'h1\'), content()(\'Hello, world!\'));')
}));
testStream.end();

function compileDone() {
var engine = _eval(testFile.contents.toString());

expect(engine).to.have.property('customProperty');
next();
}
});

it('should export compiler to YModules', function() {
var vm = require('vm');
var name = '';

vm.runInNewContext(vinylFile.contents.toString(), {
require: require,
console: console,
modules: { define: function(exportName) { name = exportName; } }
});

expect(name).to.be('BEMHTML');
});
});
});

0 comments on commit 81fc86b

Please sign in to comment.