mirror of
https://github.com/fooflington/selfdefined.git
synced 2025-11-02 14:59:03 +00:00
update
This commit is contained in:
711
node_modules/hamljs/lib/haml.js
generated
vendored
Normal file
711
node_modules/hamljs/lib/haml.js
generated
vendored
Normal file
@@ -0,0 +1,711 @@
|
||||
// Haml - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
|
||||
|
||||
var HAML = {};
|
||||
|
||||
/**
|
||||
* Version.
|
||||
*/
|
||||
|
||||
HAML.version = '0.6.2'
|
||||
|
||||
/**
|
||||
* Haml template cache.
|
||||
*/
|
||||
|
||||
HAML.cache = {}
|
||||
|
||||
/**
|
||||
* Default error context length.
|
||||
*/
|
||||
|
||||
HAML.errorContextLength = 15
|
||||
|
||||
/**
|
||||
* Self closing tags.
|
||||
*/
|
||||
|
||||
HAML.selfClosing = [
|
||||
'meta',
|
||||
'img',
|
||||
'link',
|
||||
'br',
|
||||
'hr',
|
||||
'input',
|
||||
'area',
|
||||
'base'
|
||||
]
|
||||
|
||||
/**
|
||||
* Default supported doctypes.
|
||||
*/
|
||||
|
||||
HAML.doctypes = {
|
||||
'5': '<!DOCTYPE html>',
|
||||
'xml': '<?xml version="1.0" encoding="utf-8" ?>',
|
||||
'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
|
||||
'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
|
||||
'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
|
||||
'1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
|
||||
'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
|
||||
'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
|
||||
}
|
||||
|
||||
/**
|
||||
* Default filters.
|
||||
*/
|
||||
|
||||
HAML.filters = {
|
||||
|
||||
/**
|
||||
* Return plain string.
|
||||
*/
|
||||
|
||||
plain: function(str, buf) {
|
||||
buf.push(str)
|
||||
},
|
||||
|
||||
/**
|
||||
* Wrap with CDATA tags.
|
||||
*/
|
||||
|
||||
cdata: function(str, buf) {
|
||||
buf.push('<![CDATA[\n' + str + '\n]]>')
|
||||
},
|
||||
|
||||
/**
|
||||
* Wrap with <script> and CDATA tags.
|
||||
*/
|
||||
|
||||
javascript: function(str, buf) {
|
||||
buf.push('<script type="text/javascript">\n//<![CDATA[\n' + str + '\n//]]></script>')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HamlError.
|
||||
*/
|
||||
|
||||
var HamlError = HAML.HamlError = function(msg) {
|
||||
this.name = 'HamlError'
|
||||
this.message = msg
|
||||
Error.captureStackTrace(this, HAML.render)
|
||||
}
|
||||
|
||||
/**
|
||||
* HamlError inherits from Error.
|
||||
*/
|
||||
HamlError.super_ = Error;
|
||||
HamlError.prototype = Object.create(Error.prototype, {
|
||||
constructor: {
|
||||
value: HamlError,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Lexing rules.
|
||||
*/
|
||||
|
||||
var rules = {
|
||||
indent: /^\n( *)(?! *-#)/,
|
||||
conditionalComment: /^\/(\[[^\n]+\])/,
|
||||
comment: /^\n? *\/ */,
|
||||
silentComment: /^\n? *-#([^\n]*)/,
|
||||
doctype: /^!!! *([^\n]*)/,
|
||||
escape: /^\\(.)/,
|
||||
filter: /^:(\w+) */,
|
||||
each: /^\- *each *(\w+)(?: *, *(\w+))? * in ([^\n]+)/,
|
||||
code: /^\-([^\n]+)/,
|
||||
outputCode: /^!=([^\n]+)/,
|
||||
escapeCode: /^=([^\n]+)/,
|
||||
attrs: /^\{(.*?)\}/,
|
||||
tag: /^%([-a-zA-Z][-a-zA-Z0-9:]*)/,
|
||||
class: /^\.([\w\-]+)/,
|
||||
id: /^\#([\w\-]+)/,
|
||||
text: /^([^\n]+)/
|
||||
}
|
||||
|
||||
/**
|
||||
* Return error context _str_.
|
||||
*
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function context(str) {
|
||||
return String(str)
|
||||
.substr(0, HAML.errorContextLength)
|
||||
.replace(/\n/g, '\\n')
|
||||
}
|
||||
|
||||
/**
|
||||
* Tokenize _str_.
|
||||
*
|
||||
* @param {string} str
|
||||
* @return {array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function tokenize(str) {
|
||||
var captures,
|
||||
token,
|
||||
tokens = [],
|
||||
line = 1,
|
||||
lastIndents = 0,
|
||||
str = String(str).trim().replace(/\r\n|\r|\n *\n/g, '\n')
|
||||
function error(msg){ throw new HamlError('(Haml):' + line + ' ' + msg) }
|
||||
while (str.length) {
|
||||
for (var type in rules)
|
||||
if (captures = rules[type].exec(str)) {
|
||||
token = {
|
||||
type: type,
|
||||
line: line,
|
||||
match: captures[0],
|
||||
val: captures.length > 2
|
||||
? captures.slice(1)
|
||||
: captures[1]
|
||||
}
|
||||
str = str.substr(captures[0].length)
|
||||
if (type === 'indent') ++line
|
||||
else break
|
||||
var indents = token.val.length / 2
|
||||
if (indents % 1)
|
||||
error('invalid indentation; got ' + token.val.length + ' spaces, should be multiple of 2')
|
||||
else if (indents - 1 > lastIndents)
|
||||
error('invalid indentation; got ' + indents + ', when previous was ' + lastIndents)
|
||||
else if (lastIndents > indents)
|
||||
while (lastIndents-- > indents)
|
||||
tokens.push({ type: 'outdent', line: line })
|
||||
else if (lastIndents !== indents)
|
||||
tokens.push({ type: 'indent', line: line })
|
||||
else
|
||||
tokens.push({ type: 'newline', line: line })
|
||||
lastIndents = indents
|
||||
}
|
||||
if (token) {
|
||||
if (token.type !== 'silentComment')
|
||||
tokens.push(token)
|
||||
token = null
|
||||
} else
|
||||
error('near "' + context(str) + '"')
|
||||
}
|
||||
return tokens.concat({ type: 'eof' })
|
||||
}
|
||||
|
||||
// --- Parser
|
||||
|
||||
/**
|
||||
* Initialize parser with _str_ and _options_.
|
||||
*/
|
||||
|
||||
var Parser = HAML.Parser = function (str, options) {
|
||||
options = options || {}
|
||||
this.tokens = tokenize(str)
|
||||
this.xml = options.xml
|
||||
}
|
||||
|
||||
Parser.prototype = {
|
||||
|
||||
/**
|
||||
* Lookahead a single token.
|
||||
*
|
||||
* @return {object}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
get peek() {
|
||||
return this.tokens[0]
|
||||
},
|
||||
|
||||
/**
|
||||
* Advance a single token.
|
||||
*
|
||||
* @return {object}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
get advance() {
|
||||
return this.current = this.tokens.shift()
|
||||
},
|
||||
|
||||
/**
|
||||
* outdent
|
||||
* | eof
|
||||
*/
|
||||
|
||||
get outdent() {
|
||||
switch (this.peek.type) {
|
||||
case 'eof':
|
||||
return
|
||||
case 'outdent':
|
||||
return this.advance
|
||||
default:
|
||||
throw new HamlError('expected outdent, got ' + this.peek.type)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* text
|
||||
*/
|
||||
|
||||
get text() {
|
||||
var text = this.advance.val.trim();
|
||||
|
||||
// String interpolation
|
||||
text = text.replace(/#\{(.*)\}/, '" + $1 + "')
|
||||
|
||||
this.buffer(text)
|
||||
},
|
||||
|
||||
/**
|
||||
* indent expr outdent
|
||||
*/
|
||||
|
||||
get block() {
|
||||
this.advance
|
||||
while (this.peek.type !== 'outdent' &&
|
||||
this.peek.type !== 'eof')
|
||||
this.expr
|
||||
this.outdent
|
||||
},
|
||||
|
||||
/**
|
||||
* indent expr
|
||||
*/
|
||||
|
||||
get textBlock() {
|
||||
var token,
|
||||
indents = 1
|
||||
this.advance
|
||||
while (this.peek.type !== 'eof' && indents)
|
||||
switch((token = this.advance).type) {
|
||||
case 'newline':
|
||||
this.buffer('\\n' + Array(indents).join(' ') + '')
|
||||
break
|
||||
case 'indent':
|
||||
++indents
|
||||
this.buffer('\\n' + Array(indents).join(' ') + '')
|
||||
break
|
||||
case 'outdent':
|
||||
--indents
|
||||
if (indents === 1) this.buffer('\\n')
|
||||
break
|
||||
default:
|
||||
this.buffer(token.match.replace(/"/g, '\\\"'))
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* ( attrs | class | id )*
|
||||
*/
|
||||
|
||||
get attrs() {
|
||||
var attrs = ['attrs', 'class', 'id'],
|
||||
buf = []
|
||||
|
||||
while (attrs.indexOf(this.peek.type) !== -1)
|
||||
switch (this.peek.type) {
|
||||
case 'id':
|
||||
buf.push('{ id: "' + this.advance.val + '" }')
|
||||
break
|
||||
case 'class':
|
||||
buf.push('{ class: "' + this.advance.val + '" }');
|
||||
break
|
||||
case 'attrs':
|
||||
buf.push('{ ' + this.advance.val.replace(/(for) *:/gi, '"$1":') + ' }')
|
||||
}
|
||||
|
||||
return buf.length
|
||||
? ' " + attrs([' + buf.join(', ') + ']) + "'
|
||||
: ''
|
||||
},
|
||||
|
||||
/**
|
||||
* tag
|
||||
* | tag text
|
||||
* | tag conditionalComment
|
||||
* | tag comment
|
||||
* | tag outputCode
|
||||
* | tag escapeCode
|
||||
* | tag block
|
||||
*/
|
||||
|
||||
get tag() {
|
||||
var tag = this.advance.val,
|
||||
selfClosing = !this.xml && HAML.selfClosing.indexOf(tag) !== -1
|
||||
|
||||
this.buffer('\\n<' + tag + this.attrs + (selfClosing ? '/>' : '>'));
|
||||
switch (this.peek.type) {
|
||||
case 'text':
|
||||
this.text
|
||||
break
|
||||
case 'conditionalComment':
|
||||
this.conditionalComment
|
||||
break;
|
||||
case 'comment':
|
||||
this.comment
|
||||
break
|
||||
case 'outputCode':
|
||||
this.outputCode
|
||||
break
|
||||
case 'escapeCode':
|
||||
this.escapeCode
|
||||
break
|
||||
case 'indent':
|
||||
this.block
|
||||
}
|
||||
if (!selfClosing) this.buffer('</' + tag + '>')
|
||||
},
|
||||
|
||||
/**
|
||||
* outputCode
|
||||
*/
|
||||
|
||||
get outputCode() {
|
||||
this.buffer(this.advance.val, false)
|
||||
},
|
||||
|
||||
/**
|
||||
* escapeCode
|
||||
*/
|
||||
|
||||
get escapeCode() {
|
||||
this.buffer('escape(' + this.advance.val + ')', false)
|
||||
},
|
||||
|
||||
/**
|
||||
* doctype
|
||||
*/
|
||||
|
||||
get doctype() {
|
||||
var doctype = this.advance.val.trim().toLowerCase() || 'default'
|
||||
if (doctype in HAML.doctypes)
|
||||
this.buffer(HAML.doctypes[doctype].replace(/"/g, '\\"'))
|
||||
else
|
||||
throw new HamlError("doctype `" + doctype + "' does not exist")
|
||||
},
|
||||
|
||||
/**
|
||||
* conditional comment expr
|
||||
*/
|
||||
|
||||
get conditionalComment() {
|
||||
var condition= this.advance.val
|
||||
|
||||
this.buffer('<!--' + condition + '>')
|
||||
|
||||
this.peek.type === 'indent'
|
||||
? this.block
|
||||
: this.expr
|
||||
|
||||
this.buffer('<![endif]-->')
|
||||
},
|
||||
|
||||
/**
|
||||
* comment expr
|
||||
*/
|
||||
|
||||
get comment() {
|
||||
this.advance
|
||||
this.buffer('<!-- ')
|
||||
var buf = this.peek.type === 'indent'
|
||||
? this.block
|
||||
: this.expr
|
||||
this.buffer(' -->')
|
||||
},
|
||||
|
||||
/**
|
||||
* code
|
||||
* | code block
|
||||
*/
|
||||
|
||||
get code() {
|
||||
var code = this.advance.val
|
||||
|
||||
if (this.peek.type === 'indent') {
|
||||
this.buf.push(code)
|
||||
this.buf.push('{')
|
||||
this.block
|
||||
this.buf.push('}')
|
||||
return
|
||||
}
|
||||
|
||||
this.buf.push(code)
|
||||
},
|
||||
|
||||
/**
|
||||
* filter textBlock
|
||||
*/
|
||||
|
||||
get filter() {
|
||||
var filter = this.advance.val
|
||||
if (!(filter in HAML.filters))
|
||||
throw new HamlError("filter `" + filter + "' does not exist")
|
||||
if (this.peek.type !== 'indent')
|
||||
throw new HamlError("filter `" + filter + "' expects a text block")
|
||||
|
||||
this.buf.push('HAML.filters.' + filter + '(')
|
||||
this.buf.push('(function(){')
|
||||
this.buf.push('var buf = []')
|
||||
this.textBlock
|
||||
this.buf.push('return buf.join("")')
|
||||
this.buf.push('}).call(this)')
|
||||
this.buf.push(', buf)')
|
||||
},
|
||||
|
||||
/**
|
||||
* each block
|
||||
*/
|
||||
|
||||
get iterate() {
|
||||
var each = this.advance,
|
||||
key = each.val[1],
|
||||
vals = each.val[2],
|
||||
val = each.val[0]
|
||||
|
||||
if (this.peek.type !== 'indent')
|
||||
throw new HamlError("'- each' expects a block, but got " + this.peek.type)
|
||||
|
||||
this.buf.push('for (var ' + (key || 'index') + ' in ' + vals + ') {')
|
||||
this.buf.push('var ' + val + ' = ' + vals + '[' + (key || 'index') + '];')
|
||||
|
||||
this.block
|
||||
|
||||
this.buf.push('}')
|
||||
},
|
||||
|
||||
/**
|
||||
* eof
|
||||
* | tag
|
||||
* | text*
|
||||
* | each
|
||||
* | code
|
||||
* | escape
|
||||
* | doctype
|
||||
* | filter
|
||||
* | comment
|
||||
* | conditionalComment
|
||||
* | escapeCode
|
||||
* | outputCode
|
||||
*/
|
||||
|
||||
get expr() {
|
||||
switch (this.peek.type) {
|
||||
case 'id':
|
||||
case 'class':
|
||||
this.tokens.unshift({ type: 'tag', val: 'div' })
|
||||
return this.tag
|
||||
case 'tag':
|
||||
return this.tag
|
||||
case 'text':
|
||||
var buf = []
|
||||
while (this.peek.type === 'text') {
|
||||
buf.push(this.advance.val.trim())
|
||||
if (this.peek.type === 'newline')
|
||||
this.advance
|
||||
}
|
||||
return this.buffer(buf.join(' '))
|
||||
case 'each':
|
||||
return this.iterate
|
||||
case 'code':
|
||||
return this.code
|
||||
case 'escape':
|
||||
return this.buffer(this.advance.val);
|
||||
case 'doctype':
|
||||
return this.doctype
|
||||
case 'filter':
|
||||
return this.filter
|
||||
case 'conditionalComment':
|
||||
return this.conditionalComment
|
||||
case 'comment':
|
||||
return this.comment
|
||||
case 'escapeCode':
|
||||
return this.escapeCode
|
||||
case 'outputCode':
|
||||
return this.outputCode
|
||||
case 'newline':
|
||||
case 'indent':
|
||||
case 'outdent':
|
||||
this.advance
|
||||
return this.expr
|
||||
default:
|
||||
throw new HamlError('unexpected ' + this.peek.type)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* expr*
|
||||
*/
|
||||
|
||||
get js() {
|
||||
this.buf = [
|
||||
'with (locals || {}) {',
|
||||
' var buf = [];'
|
||||
]
|
||||
|
||||
while (this.peek.type !== 'eof')
|
||||
this.expr
|
||||
|
||||
this.buf.push(' return buf.join("")')
|
||||
this.buf.push('}');
|
||||
|
||||
return this.buf.join('\n')
|
||||
},
|
||||
|
||||
buffer: function (str, quoted) {
|
||||
if (typeof quoted === 'undefined')
|
||||
var quoted = true
|
||||
|
||||
if (quoted)
|
||||
this.buf.push(' buf.push("' + str + '")')
|
||||
else
|
||||
this.buf.push(' buf.push(' + str + ')')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape html entities in _str_.
|
||||
*
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function escape(str) {
|
||||
return String(str)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/</g, '<')
|
||||
.replace(/"/g, '"')
|
||||
}
|
||||
|
||||
/**
|
||||
* Render _attrs_ to html escaped attributes.
|
||||
*
|
||||
* @param {array} attrs
|
||||
* @return {string}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function attrs(attrs) {
|
||||
var finalAttrs = {}
|
||||
, classes = []
|
||||
, buf = []
|
||||
|
||||
for (var i = 0, len = attrs.length; i < len; i++)
|
||||
for (var attrName in attrs[i])
|
||||
if (attrName === 'class')
|
||||
classes.push(attrs[i][attrName])
|
||||
else
|
||||
finalAttrs[attrName] = attrs[i][attrName]
|
||||
|
||||
if (classes.length)
|
||||
finalAttrs['class'] = classes.join(' ')
|
||||
|
||||
for (var key in finalAttrs)
|
||||
if (typeof finalAttrs[key] === 'boolean') {
|
||||
if (finalAttrs[key] === true)
|
||||
buf.push(key + '="' + key + '"')
|
||||
} else if (finalAttrs[key])
|
||||
buf.push(key + '="' + escape(finalAttrs[key]) + '"')
|
||||
return buf.join(' ')
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a function from the given `str`.
|
||||
*
|
||||
* @param {String} str
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
HAML.compile = function(str, options){
|
||||
var parser = new Parser(str, options);
|
||||
var fn = new Function('locals, attrs, escape, HAML', parser.js);
|
||||
return function(locals){
|
||||
return fn.apply(this, [locals, attrs, escape, HAML]);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Render a _str_ of haml.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - locals Local variables available to the template
|
||||
* - context Context in which the template is evaluated (becoming "this")
|
||||
* - filename Filename used to aid in error reporting
|
||||
* - cache Cache compiled javascript, requires "filename"
|
||||
* - xml Force xml support (no self-closing tags)
|
||||
*
|
||||
* @param {string} str
|
||||
* @param {object} options
|
||||
* @return {string}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
HAML.render = function(str, options) {
|
||||
var parser,
|
||||
options = options || {}
|
||||
if (options.cache && !options.filename)
|
||||
throw new Error('filename option must be passed when cache is enabled')
|
||||
return (function(){
|
||||
try {
|
||||
var fn
|
||||
if (options.cache && HAML.cache[options.filename])
|
||||
fn = HAML.cache[options.filename]
|
||||
else {
|
||||
parser = new Parser(str, options)
|
||||
fn = Function('locals, attrs, escape, HAML', parser.js)
|
||||
}
|
||||
return (options.cache
|
||||
? HAML.cache[options.filename] = fn
|
||||
: fn).call(options.context, options.locals, attrs, escape, HAML)
|
||||
} catch (err) {
|
||||
if (parser && err instanceof HamlError)
|
||||
err.message = '(Haml):' + parser.peek.line + ' ' + err.message
|
||||
else if (!(err instanceof HamlError))
|
||||
err.message = '(Haml): ' + err.message
|
||||
if (options.filename)
|
||||
err.message = err.message.replace('Haml', options.filename)
|
||||
throw err
|
||||
}
|
||||
}).call(options.context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a file containing haml and cache the parser.
|
||||
*
|
||||
* @param {string} filename
|
||||
* @param {string} encoding
|
||||
* @param {object} options
|
||||
* @param {function} callback
|
||||
* @return {void}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
HAML.renderFile = function(filename, encoding, options, callback) {
|
||||
var fs = require('fs');
|
||||
options = options || {}
|
||||
options.filename = options.filename || filename
|
||||
options.cache = options.hasOwnProperty('cache') ? options.cache : true
|
||||
|
||||
if (HAML.cache[filename]) {
|
||||
process.nextTick(function() {
|
||||
callback(null, HAML.render(null, options))
|
||||
});
|
||||
} else {
|
||||
fs.readFile(filename, encoding, function(err, str) {
|
||||
if (err) {
|
||||
callback(err)
|
||||
} else {
|
||||
callback(null, HAML.render(str, options))
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = HAML;
|
||||
Reference in New Issue
Block a user