Skip to content

Commit

Permalink
Merge pull request #450 from marko-js/v3-render-to-string
Browse files Browse the repository at this point in the history
add warnings for using render methods when you want string output
  • Loading branch information
patrick-steele-idem committed Nov 30, 2016
2 parents 91c215c + 99e7873 commit 591b912
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 53 deletions.
43 changes: 25 additions & 18 deletions docs/javascript-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ The `Template` type.

## Methods

### renderSync(templateData) : String
### renderToString(templateData) : String

Synchronously renders a template to a `String`.

Expand All @@ -113,10 +113,25 @@ Example usage:

```javascript
var template = require('./template.marko');
var html = template.renderSync({ name: 'Frank' });
var html = template.renderToString({ name: 'Frank' });
console.log(html);
```

### renderToString(templateData, callback)

Asynchronously renders a template and provides the output to the provided callback function.

```javascript
var template = require('./template.marko');
template.renderToString({ name: 'Frank' }, function(err, html, out) {
if (err) {
// Handle the error...
}

console.log(html);
});
```

### render(templateData, stream.Writable)

Renders a template to a writable stream.
Expand All @@ -130,29 +145,15 @@ template.render({ name: 'Frank' }, process.stdout);

### render(templateData, AsyncWriter)

Renders a template to an [AsyncWriter](https://github.com/marko-js/async-writer) instance that wraps an underlying stream.
Renders a template to an [AsyncWriter](https://github.com/marko-js/async-writer) instance that wraps an underlying stream. When rendering to an AsyncWriter, the writer will not be ended, automatically. You must call `out.end()` yourself.

Example usage:

```javascript
var template = require('./template.marko');
var out = require('marko').createWriter(process.stdout);
template.render({ name: 'Frank' }, out);
```

### render(templateData, callback)

Asynchronously renders a template and provides the output to the provided callback function.

```javascript
var template = require('./template.marko');
template.render({ name: 'Frank' }, function(err, html, out) {
if (err) {
// Handel the error...
}

console.log(html);
});
out.end();
```

_NOTE: The `out` argument will rarely be used, but it will be a reference to the [AsyncWriter](https://github.com/marko-js/async-writer) instance that was created to facilitate rendering of the template._
Expand All @@ -168,6 +169,12 @@ var template = require('./template.marko');
template.stream({ name: 'Frank' }).pipe(process.stdout);
```

### renderSync(templateData) : String
> Deprecated in v3, use `renderToString(templateData)` instead.
### render(templateData, callback)
> Deprecated in v3, use `renderToString(templateData, callback)` instead.
# require('marko/compiler')

## Methods
Expand Down
81 changes: 68 additions & 13 deletions runtime/deprecate.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,78 @@
var logger = typeof console !== 'undefined' && console.warn && console;
var messageCounts = {};

module.exports = function(o, methodName, message) {
if (!logger) {
return;
}
if (!logger) return;

var originalMethod = o[methodName];

var maxWarn = 20;
var currentWarn = 0;

o[methodName] = function() {
if (currentWarn < maxWarn) {
if (++currentWarn === maxWarn) {
o[methodName] = originalMethod;
}
logger.warn(message, 'Stack: ' + new Error().stack);
var remainingWarns = warn(message);

if (!remainingWarns) {
o[methodName] = originalMethod;
}

return originalMethod.apply(o, arguments);
return originalMethod.apply(this, arguments);
};
};
};

module.exports.warn = warn;

function warn(message) {
if (!logger) return 0;

var maxWarn = 20;
var stack;
messageCounts[message] = messageCounts[message] || 0;

if (messageCounts[message] < maxWarn) {
messageCounts[message]++;
try {
stack = new Error().stack.split('\n').slice(4).join('\n');
} catch(e) {}
logger.warn(red('WARNING!!') + '\n' + message + '\n' + grey(stack || ''));
}

return maxWarn - messageCounts[message];
}

var canFormat = (function () {
try {
if (process.stdout && !process.stdout.isTTY) {
return false;
}

if (process.platform === 'win32') {
return true;
}

if ('COLORTERM' in process.env) {
return true;
}

if (process.env.TERM === 'dumb') {
return false;
}

if (/^screen|^xterm|^vt100|color|ansi|cygwin|linux/i.test(process.env.TERM)) {
return true;
}
} catch(e){}

return false;
})();

function format(str, begin, end) {
begin = canFormat ? '\u001b['+begin+'m' : '';
end = canFormat ? '\u001b['+end+'m' : '';
return begin + str + end;
}

function red(str) {
return format(str, 31, 39);
}

function grey(str) {
return format(str, 90, 39);
}
59 changes: 37 additions & 22 deletions runtime/marko-runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,6 @@ exports.AsyncStream = AsyncStream;

var stream = require('./stream');

function renderCallback(renderFunc, data, globalData, callback) {
var out = new AsyncStream();
if (globalData) {
extend(out.global, globalData);
}

renderFunc(data, out);
return out.end()
.on('finish', function() {
callback(null, out.getOutput(), out);
})
.once('error', callback);
}

function Template(path, func, options) {
this.path = path;
this._ = func;
Expand All @@ -92,19 +78,33 @@ Template.prototype = {
c: function(createFunc) {
this._ = createFunc(helpers);
},
renderSync: function(data) {
renderToString: function(data, callback) {
var localData = data || {};
var out = new AsyncStream();
out.sync();

if(!callback) {
out.sync();
}

if (localData.$global) {
out.global = extend(out.global, localData.$global);
extend(out.global, localData.$global);
delete localData.$global;
}

this._(localData, out);

if(callback) {
out.end();
return out.on('finish', function() {
callback(null, out.getOutput(), out);
}).once('error', callback);
}

return out.getOutput();
},
renderSync: function(data) {
return this.renderToString(data);
},

/**
* Renders a template to either a stream (if the last
Expand All @@ -126,6 +126,14 @@ Template.prototype = {
* @return {AsyncStream} Returns the AsyncStream instance that the template is rendered to
*/
render: function(data, out, callback) {
if(typeof out === 'function') {
require('./deprecate').warn(
'The render callback will no longer receive a string in Marko v4. '+
'Use `renderToString(data, callback)` instead.'
);
return this.renderToString(data, out /* callback */);
}

var renderFunc = this._;
var finalData;
var globalData;
Expand All @@ -141,11 +149,6 @@ Template.prototype = {
finalData = {};
}

if (typeof out === 'function') {
// Short circuit for render(data, callback)
return renderCallback(renderFunc, finalData, globalData, out);
}

// NOTE: We create new vars here to avoid a V8 de-optimization due
// to the following:
// Assignment to parameter in arguments object
Expand All @@ -154,6 +157,11 @@ Template.prototype = {
var shouldEnd = false;

if (arguments.length === 3) {
require('./deprecate').warn(
'Support for `render(data, out, callback)` will be removed in v4. ' +
'If you would like to discuss, see: https://github.com/marko-js/marko/issues/451'
);

// render(data, out, callback)
if (!finalOut || !finalOut.isAsyncStream) {
finalOut = new AsyncStream(globalData, finalOut);
Expand Down Expand Up @@ -202,6 +210,13 @@ Template.prototype = {
}
};

require('./deprecate')(
Template.prototype,
'renderSync',
'Please use `renderToString` instead of `renderSync`. '+
'The behavior of `renderSync` is changing in the next version of Marko.'
);

if (stream) {
Readable = function(template, data, options) {
Readable.$super.call(this);
Expand Down

0 comments on commit 591b912

Please sign in to comment.