Socket
Socket
Sign inDemoInstall

jade-code-gen

Package Overview
Dependencies
19
Maintainers
5
Versions
4
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.3 to 0.0.4

350

index.js

@@ -6,4 +6,4 @@ 'use strict';

var runtime = require('jade-runtime');
var compileAttrs = require('jade-attrs');
var selfClosing = require('void-elements');
var parseJSExpression = require('character-parser').parseMax;
var constantinople = require('constantinople');

@@ -13,2 +13,8 @@ var stringify = require('js-stringify');

// This is used to prevent pretty printing inside certain tags
var WHITE_SPACE_SENSITIVE_TAGS = {
pre: true,
textarea: true
};
var INTERNAL_VARIABLES = [

@@ -21,3 +27,3 @@ 'jade',

'jade_debug_sources',
'buf'
'jade_html'
];

@@ -50,2 +56,3 @@

this.node = node;
this.bufferedConcatenationCount = 0;
this.hasCompiledDoctype = false;

@@ -63,5 +70,6 @@ this.hasCompiledTag = false;

this.dynamicMixins = false;
this.eachCount = 0;
if (options.doctype) this.setDoctype(options.doctype);
this.runtimeFunctionsUsed = [];
this.inlineRuntimeFunctions = options.inlineRuntimeFunctions;
this.inlineRuntimeFunctions = options.inlineRuntimeFunctions || false;
if (this.debug && this.inlineRuntimeFunctions) {

@@ -146,3 +154,3 @@ this.runtimeFunctionsUsed.push('rethrow');

}
return buildRuntime(this.runtimeFunctionsUsed) + 'function ' + (this.options.templateName || 'template') + '(locals) {var buf = [], jade_mixins = {}, jade_interp;' + js + ';return buf.join("");}';
return buildRuntime(this.runtimeFunctionsUsed) + 'function ' + (this.options.templateName || 'template') + '(locals) {var jade_html = "", jade_mixins = {}, jade_interp;' + js + ';return jade_html;}';
},

@@ -173,22 +181,4 @@

buffer: function (str, interpolate) {
buffer: function (str) {
var self = this;
if (interpolate) {
var match = /(\\)?([#!]){((?:.|\n)*)$/.exec(str);
if (match) {
this.buffer(str.substr(0, match.index), false);
if (match[1]) { // escape
this.buffer(match[2] + '{', false);
this.buffer(match[3], true);
return;
} else {
var rest = match[3];
var range = parseJSExpression(rest);
var code = ('!' == match[2] ? '' : this.runtime('escape')) + "((jade_interp = " + range.src + ") == null ? '' : jade_interp)";
this.bufferExpression(code);
this.buffer(rest.substr(range.end + 1), true);
return;
}
}
}

@@ -198,9 +188,13 @@ str = stringify(str);

if (this.lastBufferedIdx == this.buf.length) {
if (this.lastBufferedType === 'code') this.lastBuffered += ' + "';
if (this.lastBufferedIdx == this.buf.length && this.bufferedConcatenationCount < 100) {
if (this.lastBufferedType === 'code') {
this.lastBuffered += ' + "';
this.bufferedConcatenationCount++;
}
this.lastBufferedType = 'text';
this.lastBuffered += str;
this.buf[this.lastBufferedIdx - 1] = 'buf.push(' + this.bufferStartChar + this.lastBuffered + '");'
this.buf[this.lastBufferedIdx - 1] = 'jade_html = jade_html + ' + this.bufferStartChar + this.lastBuffered + '";';
} else {
this.buf.push('buf.push("' + str + '");');
this.bufferedConcatenationCount = 0;
this.buf.push('jade_html = jade_html + "' + str + '";');
this.lastBufferedType = 'text';

@@ -222,11 +216,13 @@ this.bufferStartChar = '"';

if (isConstant(src)) {
return this.buffer(toConstant(src) + '', false)
return this.buffer(toConstant(src) + '')
}
if (this.lastBufferedIdx == this.buf.length) {
if (this.lastBufferedIdx == this.buf.length && this.bufferedConcatenationCount < 100) {
this.bufferedConcatenationCount++;
if (this.lastBufferedType === 'text') this.lastBuffered += '"';
this.lastBufferedType = 'code';
this.lastBuffered += ' + (' + src + ')';
this.buf[this.lastBufferedIdx - 1] = 'buf.push(' + this.bufferStartChar + this.lastBuffered + ');'
this.buf[this.lastBufferedIdx - 1] = 'jade_html = jade_html + (' + this.bufferStartChar + this.lastBuffered + ');';
} else {
this.buf.push('buf.push(' + src + ');');
this.bufferedConcatenationCount = 0;
this.buf.push('jade_html = jade_html + (' + src + ');');
this.lastBufferedType = 'code';

@@ -253,3 +249,3 @@ this.bufferStartChar = '';

if (this.parentIndents)
this.buf.push("buf.push.apply(buf, jade_indent);");
this.buf.push('jade_html = jade_html + jade_indent.join("");');
},

@@ -264,5 +260,16 @@

visit: function(node){
visit: function(node, parent){
var debug = this.debug;
if (!node) {
var msg;
if (parent) {
msg = 'A child of ' + parent.type + ' (' + (parent.filename || 'Jade') + ':' + parent.line + ')';
} else {
msg = 'A top-level node';
}
msg += ' is ' + node + ', expected a Jade AST Node.';
throw new TypeError(msg);
}
if (debug && node.debug !== false && node.type !== 'Block') {

@@ -276,2 +283,26 @@ if (node.line) {

if (!this['visit' + node.type]) {
var msg;
if (parent) {
msg = 'A child of ' + parent.type
} else {
msg = 'A top-level node';
}
msg += ' (' + (node.filename || 'Jade') + ':' + node.line + ')'
+ ' is of type ' + node.type + ','
+ ' which is not supported by jade-code-gen.'
switch (node.type) {
case 'Filter':
msg += ' Please use jade-filters to preprocess this AST.'
break;
case 'Extends':
case 'Include':
case 'NamedBlock':
case 'FileReference': // unlikely but for the sake of completeness
msg += ' Please use jade-linker to preprocess this AST.'
break;
}
throw new TypeError(msg);
}
this.visitNode(node);

@@ -303,3 +334,3 @@ //this.buf.push('');

this.buf.push('switch (' + node.expr + '){');
this.visit(node.block);
this.visit(node.block, node);
this.buf.push('}');

@@ -323,3 +354,3 @@ this.withinCase = _;

if (node.block) {
this.visit(node.block);
this.visit(node.block, node);
this.buf.push(' break;');

@@ -351,7 +382,7 @@ }

visitBlock: function(block){
var escape = this.escape;
var escapePrettyMode = this.escapePrettyMode;
var pp = this.pp;
// Pretty print multi-line text
if (pp && block.nodes.length > 1 && !escape &&
if (pp && block.nodes.length > 1 && !escapePrettyMode &&
block.nodes[0].type === 'Text' && block.nodes[1].type === 'Text' ) {

@@ -362,3 +393,3 @@ this.prettyIndent(1, true);

// Pretty print text
if (pp && i > 0 && !escape &&
if (pp && i > 0 && !escapePrettyMode &&
block.nodes[i].type === 'Text' && block.nodes[i-1].type === 'Text' &&

@@ -368,3 +399,3 @@ /\n$/.test(block.nodes[i - 1].val)) {

}
this.visit(block.nodes[i]);
this.visit(block.nodes[i], block);
}

@@ -439,3 +470,3 @@ },

this.indents = 0;
this.visit(mixin.block);
this.visit(mixin.block, mixin);
this.indents = _indents;

@@ -456,3 +487,7 @@ this.parentIndents--;

}
this.buf.push('attributes: ' + this.runtime('merge') + '([' + attrsBlocks.join(',') + '])');
if (attrsBlocks.length > 1) {
this.buf.push('attributes: ' + this.runtime('merge') + '([' + attrsBlocks.join(',') + '])');
} else {
this.buf.push('attributes: ' + attrsBlocks[0]);
}
} else if (attrs.length) {

@@ -491,3 +526,3 @@ var val = this.attrs(attrs);

this.parentIndents++;
this.visit(block);
this.visit(block, mixin);
this.parentIndents--;

@@ -505,6 +540,7 @@ this.buf.push('};');

* @param {Tag} tag
* @param {boolean} interpolated
* @api public
*/
visitTag: function(tag){
visitTag: function(tag, interpolated){
this.indents++;

@@ -516,7 +552,7 @@ var name = tag.name

function bufferName() {
if (tag.buffer) self.bufferExpression(name);
if (interpolated) self.bufferExpression(tag.expr);
else self.buffer(name);
}
if ('pre' == tag.name) this.escape = true;
if (WHITE_SPACE_SENSITIVE_TAGS[tag.name] === true) this.escapePrettyMode = true;

@@ -537,7 +573,10 @@ if (!this.hasCompiledTag) {

this.visitAttributes(tag.attrs, tag.attributeBlocks.slice());
this.terse
? this.buffer('>')
: this.buffer('/>');
if (this.terse && !tag.selfClosing) {
this.buffer('>');
} else {
this.buffer('/>');
}
// if it is non-empty throw an error
if (tag.block &&
if (tag.code ||
tag.block &&
!(tag.block.type === 'Block' && tag.block.nodes.length === 0) &&

@@ -556,6 +595,6 @@ tag.block.nodes.some(function (tag) {

if (tag.code) this.visitCode(tag.code);
this.visit(tag.block);
this.visit(tag.block, tag);
// pretty print
if (pp && !tag.isInline && 'pre' != tag.name && !tagCanInline(tag))
if (pp && !tag.isInline && WHITE_SPACE_SENSITIVE_TAGS[tag.name] !== true && !tagCanInline(tag))
this.prettyIndent(0, true);

@@ -568,3 +607,3 @@

if ('pre' == tag.name) this.escape = false;
if (WHITE_SPACE_SENSITIVE_TAGS[tag.name] === true) this.escapePrettyMode = false;

@@ -575,2 +614,13 @@ this.indents--;

/**
* Visit InterpolatedTag.
*
* @param {InterpolatedTag} tag
* @api public
*/
visitInterpolatedTag: function(tag) {
return this.visitTag(tag, true);
},
/**
* Visit `text` node.

@@ -583,3 +633,3 @@ *

visitText: function(text){
this.buffer(text.val, true);
this.buffer(text.val);
},

@@ -601,2 +651,13 @@

/**
* Visit a `YieldBlock`.
*
* This is necessary since we allow compiling a file with `yield`.
*
* @param {YieldBlock} block
* @api public
*/
visitYieldBlock: function(block) {},
/**
* Visit a `BlockComment`.

@@ -612,3 +673,3 @@ *

this.buffer('<!--' + (comment.val || ''));
this.visit(comment.block);
this.visit(comment.block, comment);
if (this.pp) this.prettyIndent(1, true);

@@ -636,3 +697,3 @@ this.buffer('-->');

val = 'null == (jade_interp = '+val+') ? "" : jade_interp';
if (code.escape) val = this.runtime('escape') + '(' + val + ')';
if (code.mustEscape !== false) val = this.runtime('escape') + '(' + val + ')';
this.bufferExpression(val);

@@ -646,3 +707,3 @@ } else {

if (!code.buffer) this.buf.push('{');
this.visit(code.block);
this.visit(code.block, code);
if (!code.buffer) this.buf.push('}');

@@ -653,2 +714,40 @@ }

/**
* Visit `Conditional`.
*
* @param {Conditional} cond
* @api public
*/
visitConditional: function(cond){
var test = cond.test;
this.buf.push('if (' + test + ') {');
this.visit(cond.consequent, cond);
this.buf.push('}')
if (cond.alternate) {
if (cond.alternate.type === 'Conditional') {
this.buf.push('else')
this.visitConditional(cond.alternate);
} else {
this.buf.push('else {');
this.visit(cond.alternate, cond);
this.buf.push('}');
}
}
},
/**
* Visit `While`.
*
* @param {While} loop
* @api public
*/
visitWhile: function(loop){
var test = loop.test;
this.buf.push('while (' + test + ') {');
this.visit(loop.block, loop);
this.buf.push('}');
},
/**
* Visit `each` block.

@@ -661,42 +760,46 @@ *

visitEach: function(each){
var indexVarName = each.key || 'jade_index' + this.eachCount
, objVarName = 'jade_obj' + this.eachCount
, lengthVarName = 'jade_length' + this.eachCount;
this.eachCount++;
this.buf.push(''
+ '// iterate ' + each.obj + '\n'
+ ';(function(){\n'
+ ' var $$obj = ' + each.obj + ';\n'
+ ' if (\'number\' == typeof $$obj.length) {\n');
+ 'var ' + objVarName + ' = ' + each.obj + ';\n'
+ 'if (\'number\' == typeof ' + objVarName + '.length) {\n');
if (each.alternative) {
this.buf.push(' if ($$obj.length) {');
if (each.alternate) {
this.buf.push('if (' + objVarName + '.length) {');
}
this.buf.push(''
+ ' for (var ' + each.key + ' = 0, $$l = $$obj.length; ' + each.key + ' < $$l; ' + each.key + '++) {\n'
+ ' var ' + each.val + ' = $$obj[' + each.key + '];\n');
+ ' for (var ' + indexVarName + ' = 0, ' + lengthVarName + ' = ' + objVarName + '.length; ' + indexVarName + ' < ' + lengthVarName + '; ' + indexVarName + '++) {\n'
+ ' var ' + each.val + ' = ' + objVarName + '[' + indexVarName + '];\n');
this.visit(each.block);
this.visit(each.block, each);
this.buf.push(' }\n');
this.buf.push(' }\n');
if (each.alternative) {
this.buf.push(' } else {');
this.visit(each.alternative);
this.buf.push(' }');
if (each.alternate) {
this.buf.push('} else {');
this.visit(each.alternate, each);
this.buf.push('}');
}
this.buf.push(''
+ ' } else {\n'
+ ' var $$l = 0;\n'
+ ' for (var ' + each.key + ' in $$obj) {\n'
+ ' $$l++;'
+ ' var ' + each.val + ' = $$obj[' + each.key + '];\n');
+ '} else {\n'
+ ' var ' + lengthVarName + ' = 0;\n'
+ ' for (var ' + indexVarName + ' in ' + objVarName + ') {\n'
+ ' ' + lengthVarName + '++;\n'
+ ' var ' + each.val + ' = ' + objVarName + '[' + indexVarName + '];\n');
this.visit(each.block);
this.visit(each.block, each);
this.buf.push(' }\n');
if (each.alternative) {
this.buf.push(' if ($$l === 0) {');
this.visit(each.alternative);
this.buf.push(' }');
this.buf.push(' }\n');
if (each.alternate) {
this.buf.push(' if (' + lengthVarName + ' === 0) {');
this.visit(each.alternate, each);
this.buf.push(' }');
}
this.buf.push(' }\n}).call(this);\n');
this.buf.push('}\n');
},

@@ -732,76 +835,11 @@

attrs: function(attrs, buffer){
var buf = [];
var classes = [];
var classEscaping = [];
var addAttribute = function (key, val, escaped) {
if (isConstant(val)) {
if (buffer) {
this.buffer(runtime.attr(key, toConstant(val), escaped, this.terse));
} else {
var val = toConstant(val);
if (escaped && !(key.indexOf('data') === 0 && typeof val !== 'string')) {
val = runtime.escape(val);
}
buf.push(stringify(key) + ': ' + stringify(val));
}
} else {
if (buffer) {
this.bufferExpression(this.runtime('attr') + '("' + key + '", ' + val + ', ' + stringify(escaped) + ', ' + stringify(this.terse) + ')');
} else {
var val = val;
if (escaped && !(key.indexOf('data') === 0)) {
val = this.runtime('escape') + '(' + val + ')';
} else if (escaped) {
val = '(typeof (jade_interp = ' + val + ') == "string" ? ' + this.runtime('escape') + '(jade_interp) : jade_interp)';
}
buf.push(stringify(key) + ': ' + val);
}
}
}.bind(this);
attrs.forEach(function(attr){
var key = attr.name;
var val = attr.val;
var escaped = attr.escaped;
if (key === 'class') {
classes.push(val);
classEscaping.push(escaped);
} else {
if (key === 'style') {
if (isConstant(val)) {
val = stringify(runtime.style(toConstant(val)));
} else {
val = this.runtime('style') + '(' + val + ')';
}
}
addAttribute(key, val, escaped);
}
}.bind(this));
if (classes.length) {
if (classes.every(isConstant)) {
addAttribute(
'class',
stringify(runtime.classes(classes.map(toConstant), classEscaping)),
false
);
} else {
classes = classes.map(function (cls, i) {
if (isConstant(cls)) {
cls = stringify(runtime.classes(
[toConstant(cls)],
classEscaping[i]
));
classEscaping[i] = false;
}
return cls;
});
addAttribute(
'class',
this.runtime('classes') + '([' + classes.join(',') + '], ' + stringify(classEscaping) + ')',
false
);
}
var res = compileAttrs(attrs, {
terse: this.terse,
format: buffer ? 'html' : 'object',
runtime: this.runtime.bind(this)
});
if (buffer) {
this.bufferExpression(res);
}
return '{' + buf.join(',') + '}';
return res;
}

@@ -814,2 +852,6 @@ };

if (node.type === 'Block') return node.nodes.every(isInline);
// When there is a YieldBlock here, it is an indication that the file is
// expected to be included but is not. If this is the case, the block
// must be empty.
if (node.type === 'YieldBlock') return true;
return (node.type === 'Text' && !/\n/.test(node.val)) || node.isInline;

@@ -816,0 +858,0 @@ }

{
"name": "jade-code-gen",
"version": "0.0.3",
"version": "0.0.4",
"description": "Default code-generator for jade. It generates HTML via a JavaScript template function.",
"keywords": [],
"keywords": [
"jade"
],
"dependencies": {
"character-parser": "^1.2.2",
"constantinople": "^3.0.1",
"doctypes": "^1.0.0",
"jade-attrs": "^2.0.0",
"jade-runtime": "^1.0.0",

@@ -16,3 +18,2 @@ "js-stringify": "^1.0.1",

"devDependencies": {
"mocha": "*"
},

@@ -28,2 +29,2 @@ "scripts": {

"license": "MIT"
}
}

@@ -15,15 +15,49 @@ # jade-code-gen

Options:
```js
var generateCode = require('jade-code-gen');
```
- pretty (boolean)
- compileDebug (boolean) - defaults to `true`
- doctype (string)
- includeRuntimeFunctions (boolean)
- globals (array of strings)
- self (boolean)
- includeSources (map of filename to source string)
- templateName (string) - defaults to `'template'`
### `generateCode(ast, options)`
Generate a JavaScript function string for the given AST.
`ast` is a fully expanded AST for Jade, with all inclusion, extends, and filters resolved.
`options` may contain the following properties that have the same meaning as the options with the same names in `jade`:
- pretty (boolean): default is `false`
- compileDebug (boolean): default is `false`
- doctype (string): default is `undefined`
- inlineRuntimeFunctions (boolean): default is `false`
- globals (array of strings): default is `[]`
- self (boolean): default is `false`
In addition to above, `jade-code-gen` has the following unique options:
- includeSources (object): map of filename to source string; used if `compileDebug` is `true`; default is `undefined`
- templateName (string): the name of the generated function; default is `'template'`
```js
var lex = require('jade-lexer');
var parse = require('jade-parser');
var generateCode = require('jade-code-gen');
var funcStr = generateCode(parse(lex('p Hello world!')), {
compileDebug: false,
pretty: true,
inlineRuntimeFunctions: false,
templateName: 'helloWorld'
});
var func = Function('locals', funcStr);
func();
//=> '\n<p>Hello world!</p>'
```
### `new generateCode.CodeGenerator(ast, options)`
The constructor for the internal class of the code generator. You shouldn't need to use this for most purposes.
## License
MIT
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc