You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
3.7 KiB
112 lines
3.7 KiB
'use strict'; |
|
|
|
var dirname = require('path').dirname; |
|
var constantinople = require('constantinople'); |
|
var walk = require('pug-walk'); |
|
var error = require('pug-error'); |
|
var runFilter = require('./run-filter'); |
|
|
|
module.exports = handleFilters; |
|
function handleFilters(ast, filters, options, filterAliases) { |
|
options = options || {}; |
|
walk(ast, function (node) { |
|
var dir = node.filename ? dirname(node.filename) : null; |
|
if (node.type === 'Filter') { |
|
handleNestedFilters(node, filters, options, filterAliases); |
|
var text = getBodyAsText(node); |
|
var attrs = getAttributes(node, options); |
|
attrs.filename = node.filename; |
|
node.type = 'Text'; |
|
node.val = filterWithFallback(node, text, attrs); |
|
} else if (node.type === 'RawInclude' && node.filters.length) { |
|
var firstFilter = node.filters.pop(); |
|
var attrs = getAttributes(firstFilter, options); |
|
var filename = attrs.filename = node.file.fullPath; |
|
var str = node.file.str; |
|
node.type = 'Text'; |
|
node.val = filterFileWithFallback(firstFilter, filename, str, attrs); |
|
node.filters.slice().reverse().forEach(function (filter) { |
|
var attrs = getAttributes(filter, options); |
|
attrs.filename = filename; |
|
node.val = filterWithFallback(filter, node.val, attrs); |
|
}); |
|
node.filters = undefined; |
|
node.file = undefined; |
|
} |
|
|
|
function filterWithFallback(filter, text, attrs, funcName) { |
|
try { |
|
var filterName = getFilterName(filter); |
|
if (filters && filters[filterName]) { |
|
return filters[filterName](text, attrs); |
|
} else { |
|
return runFilter(filterName, text, attrs, dir, funcName); |
|
} |
|
} catch (ex) { |
|
if (ex.code === 'UNKNOWN_FILTER') { |
|
throw error(ex.code, ex.message, filter); |
|
} |
|
throw ex; |
|
} |
|
} |
|
|
|
function filterFileWithFallback(filter, filename, text, attrs) { |
|
var filterName = getFilterName(filter); |
|
if (filters && filters[filterName]) { |
|
return filters[filterName](text, attrs); |
|
} else { |
|
return filterWithFallback(filter, filename, attrs, 'renderFile'); |
|
} |
|
} |
|
}, {includeDependencies: true}); |
|
function getFilterName(filter) { |
|
var filterName = filter.name; |
|
if (filterAliases && filterAliases[filterName]) { |
|
filterName = filterAliases[filterName]; |
|
if (filterAliases[filterName]) { |
|
throw error( |
|
'FILTER_ALISE_CHAIN', |
|
'The filter "' + filter.name + '" is an alias for "' + filterName + |
|
'", which is an alias for "' + filterAliases[filterName] + |
|
'". Pug does not support chains of filter aliases.', |
|
filter |
|
); |
|
} |
|
} |
|
return filterName; |
|
} |
|
return ast; |
|
}; |
|
|
|
function handleNestedFilters(node, filters, options, filterAliases) { |
|
if (node.block.nodes[0] && node.block.nodes[0].type === 'Filter') { |
|
node.block.nodes[0] = handleFilters(node.block, filters, options, filterAliases).nodes[0]; |
|
} |
|
} |
|
|
|
function getBodyAsText(node) { |
|
return node.block.nodes.map( |
|
function(node){ return node.val; } |
|
).join(''); |
|
} |
|
|
|
function getAttributes(node, options) { |
|
var attrs = {}; |
|
node.attrs.forEach(function (attr) { |
|
try { |
|
attrs[attr.name] = attr.val === true ? true : constantinople.toConstant(attr.val); |
|
} catch (ex) { |
|
if (/not constant/.test(ex.message)) { |
|
throw error('FILTER_OPTION_NOT_CONSTANT', ex.message + ' All filters are rendered compile-time so filter options must be constants.', node); |
|
} |
|
throw ex; |
|
} |
|
}); |
|
var opts = options[node.name] || {}; |
|
Object.keys(opts).forEach(function (opt) { |
|
if (!attrs.hasOwnProperty(opt)) { |
|
attrs[opt] = opts[opt]; |
|
} |
|
}); |
|
return attrs; |
|
}
|
|
|