mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-15 04:10:40 -07:00
eslint
This commit is contained in:
+56
-58
@@ -1,68 +1,66 @@
|
||||
const lexical = require('./lexical.js');
|
||||
const Syntax = require('./syntax.js');
|
||||
const assert = require('./util/assert.js');
|
||||
const _ = require('./util/underscore.js');
|
||||
const lexical = require('./lexical.js')
|
||||
const Syntax = require('./syntax.js')
|
||||
const assert = require('./util/assert.js')
|
||||
const _ = require('./util/underscore.js')
|
||||
|
||||
var valueRE = new RegExp(`${lexical.value.source}`, 'g');
|
||||
var valueRE = new RegExp(`${lexical.value.source}`, 'g')
|
||||
|
||||
module.exports = function(options) {
|
||||
options = _.assign({}, options);
|
||||
var filters = {};
|
||||
module.exports = function (options) {
|
||||
options = _.assign({}, options)
|
||||
var filters = {}
|
||||
|
||||
var _filterInstance = {
|
||||
render: function(output, scope) {
|
||||
var args = this.args.map(arg => Syntax.evalValue(arg, scope));
|
||||
args.unshift(output);
|
||||
return this.filter.apply(null, args);
|
||||
},
|
||||
parse: function(str) {
|
||||
var match = lexical.filterLine.exec(str);
|
||||
assert(match, 'illegal filter: ' + str);
|
||||
var _filterInstance = {
|
||||
render: function (output, scope) {
|
||||
var args = this.args.map(arg => Syntax.evalValue(arg, scope))
|
||||
args.unshift(output)
|
||||
return this.filter.apply(null, args)
|
||||
},
|
||||
parse: function (str) {
|
||||
var match = lexical.filterLine.exec(str)
|
||||
assert(match, 'illegal filter: ' + str)
|
||||
|
||||
var name = match[1], argList = match[2] || '', filter = filters[name];
|
||||
if (typeof filter !== 'function'){
|
||||
if(options.strict_filters){
|
||||
throw new TypeError(`undefined filter: ${name}`);
|
||||
}
|
||||
this.name= name;
|
||||
this.filter= x => x;
|
||||
this.args= [];
|
||||
return this;
|
||||
//return {
|
||||
//name: name,
|
||||
//error: new TypeError(`undefined filter: ${name}`)
|
||||
//};
|
||||
}
|
||||
|
||||
var args = [];
|
||||
while(match = valueRE.exec(argList.trim())){
|
||||
var v = match[0];
|
||||
var re = new RegExp(`${v}\\s*:`, 'g');
|
||||
re.test(match.input) ? args.push(`'${v}'`) : args.push(v);
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
this.filter = filter;
|
||||
this.args = args;
|
||||
|
||||
return this;
|
||||
var name = match[1]
|
||||
var argList = match[2] || ''
|
||||
var filter = filters[name]
|
||||
if (typeof filter !== 'function') {
|
||||
if (options.strict_filters) {
|
||||
throw new TypeError(`undefined filter: ${name}`)
|
||||
}
|
||||
};
|
||||
this.name = name
|
||||
this.filter = x => x
|
||||
this.args = []
|
||||
return this
|
||||
}
|
||||
|
||||
function construct(str) {
|
||||
var instance = Object.create(_filterInstance);
|
||||
return instance.parse(str);
|
||||
var args = []
|
||||
while ((match = valueRE.exec(argList.trim()))) {
|
||||
var v = match[0]
|
||||
var re = new RegExp(`${v}\\s*:`, 'g')
|
||||
re.test(match.input) ? args.push(`'${v}'`) : args.push(v)
|
||||
}
|
||||
|
||||
this.name = name
|
||||
this.filter = filter
|
||||
this.args = args
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
function register(name, filter) {
|
||||
filters[name] = filter;
|
||||
}
|
||||
function construct (str) {
|
||||
var instance = Object.create(_filterInstance)
|
||||
return instance.parse(str)
|
||||
}
|
||||
|
||||
function clear() {
|
||||
filters = {};
|
||||
}
|
||||
function register (name, filter) {
|
||||
filters[name] = filter
|
||||
}
|
||||
|
||||
return {
|
||||
construct, register, clear
|
||||
};
|
||||
};
|
||||
function clear () {
|
||||
filters = {}
|
||||
}
|
||||
|
||||
return {
|
||||
construct, register, clear
|
||||
}
|
||||
}
|
||||
|
||||
+84
-61
@@ -1,92 +1,115 @@
|
||||
// quote related
|
||||
var singleQuoted = /'[^']*'/;
|
||||
var doubleQuoted = /"[^"]*"/;
|
||||
var quoted = new RegExp(`${singleQuoted.source}|${doubleQuoted.source}`);
|
||||
var quoteBalanced = new RegExp(`(?:${quoted.source}|[^'"])*`);
|
||||
var singleQuoted = /'[^']*'/
|
||||
var doubleQuoted = /"[^"]*"/
|
||||
var quoted = new RegExp(`${singleQuoted.source}|${doubleQuoted.source}`)
|
||||
var quoteBalanced = new RegExp(`(?:${quoted.source}|[^'"])*`)
|
||||
|
||||
// basic types
|
||||
var integer = /-?\d+/;
|
||||
var number = /-?\d+\.?\d*|\.?\d+/;
|
||||
var bool = /true|false/;
|
||||
var integer = /-?\d+/
|
||||
var number = /-?\d+\.?\d*|\.?\d+/
|
||||
var bool = /true|false/
|
||||
|
||||
// peoperty access
|
||||
var identifier = /[\w-]+/;
|
||||
var subscript = new RegExp(`\\[(?:${quoted.source}|[\\w-\\.]+)\\]`);
|
||||
var literal = new RegExp(`(?:${quoted.source}|${bool.source}|${number.source})`);
|
||||
var variable = new RegExp(`${identifier.source}(?:\\.${identifier.source}|${subscript.source})*`);
|
||||
var identifier = /[\w-]+/
|
||||
var subscript = new RegExp(`\\[(?:${quoted.source}|[\\w-\\.]+)\\]`)
|
||||
var literal = new RegExp(`(?:${quoted.source}|${bool.source}|${number.source})`)
|
||||
var variable = new RegExp(`${identifier.source}(?:\\.${identifier.source}|${subscript.source})*`)
|
||||
|
||||
// range related
|
||||
var rangeLimit = new RegExp(`(?:${variable.source}|${number.source})`);
|
||||
var range = new RegExp(`\\(${rangeLimit.source}\\.\\.${rangeLimit.source}\\)`);
|
||||
var rangeCapture = new RegExp(`\\((${rangeLimit.source})\\.\\.(${rangeLimit.source})\\)`);
|
||||
var rangeLimit = new RegExp(`(?:${variable.source}|${number.source})`)
|
||||
var range = new RegExp(`\\(${rangeLimit.source}\\.\\.${rangeLimit.source}\\)`)
|
||||
var rangeCapture = new RegExp(`\\((${rangeLimit.source})\\.\\.(${rangeLimit.source})\\)`)
|
||||
|
||||
var value = new RegExp(`(?:${variable.source}|${literal.source}|${range.source})`);
|
||||
var value = new RegExp(`(?:${variable.source}|${literal.source}|${range.source})`)
|
||||
|
||||
// hash related
|
||||
var hash = new RegExp(`(?:${identifier.source})\\s*:\\s*(?:${value.source})`);
|
||||
var hashCapture = new RegExp(`(${identifier.source})\\s*:\\s*(${value.source})`, 'g');
|
||||
var hash = new RegExp(`(?:${identifier.source})\\s*:\\s*(?:${value.source})`)
|
||||
var hashCapture = new RegExp(`(${identifier.source})\\s*:\\s*(${value.source})`, 'g')
|
||||
|
||||
// full match
|
||||
var tagLine = new RegExp(`^\\s*(${identifier.source})\\s*([\\s\\S]*)\\s*$`);
|
||||
var literalLine = new RegExp(`^${literal.source}$`, 'i');
|
||||
var variableLine = new RegExp(`^${variable.source}$`);
|
||||
var numberLine = new RegExp(`^${number.source}$`);
|
||||
var boolLine = new RegExp(`^${bool.source}$`, 'i');
|
||||
var quotedLine = new RegExp(`^${quoted.source}$`);
|
||||
var rangeLine = new RegExp(`^${rangeCapture.source}$`);
|
||||
var integerLine = new RegExp(`^${integer.source}$`);
|
||||
var tagLine = new RegExp(`^\\s*(${identifier.source})\\s*([\\s\\S]*)\\s*$`)
|
||||
var literalLine = new RegExp(`^${literal.source}$`, 'i')
|
||||
var variableLine = new RegExp(`^${variable.source}$`)
|
||||
var numberLine = new RegExp(`^${number.source}$`)
|
||||
var boolLine = new RegExp(`^${bool.source}$`, 'i')
|
||||
var quotedLine = new RegExp(`^${quoted.source}$`)
|
||||
var rangeLine = new RegExp(`^${rangeCapture.source}$`)
|
||||
var integerLine = new RegExp(`^${integer.source}$`)
|
||||
|
||||
// filter related
|
||||
var valueDeclaration = new RegExp(`(?:${identifier.source}\\s*:\\s*)?${value.source}`)
|
||||
var valueList = new RegExp(`${valueDeclaration.source}(\\s*,\\s*${valueDeclaration.source})*`);
|
||||
var filter = new RegExp(`${identifier.source}(?:\\s*:\\s*${valueList.source})?`, 'g');
|
||||
var filterCapture = new RegExp(`(${identifier.source})(?:\\s*:\\s*(${valueList.source}))?`);
|
||||
var filterLine = new RegExp(`^${filterCapture.source}$`);
|
||||
var valueList = new RegExp(`${valueDeclaration.source}(\\s*,\\s*${valueDeclaration.source})*`)
|
||||
var filter = new RegExp(`${identifier.source}(?:\\s*:\\s*${valueList.source})?`, 'g')
|
||||
var filterCapture = new RegExp(`(${identifier.source})(?:\\s*:\\s*(${valueList.source}))?`)
|
||||
var filterLine = new RegExp(`^${filterCapture.source}$`)
|
||||
|
||||
var operators = [
|
||||
/\s+or\s+/,
|
||||
/\s+and\s+/,
|
||||
/==|!=|<=|>=|<|>|\s+contains\s+/
|
||||
];
|
||||
/\s+or\s+/,
|
||||
/\s+and\s+/,
|
||||
/==|!=|<=|>=|<|>|\s+contains\s+/
|
||||
]
|
||||
|
||||
function isInteger(str){
|
||||
return integerLine.test(str);
|
||||
function isInteger (str) {
|
||||
return integerLine.test(str)
|
||||
}
|
||||
|
||||
function isLiteral(str) {
|
||||
return literalLine.test(str);
|
||||
function isLiteral (str) {
|
||||
return literalLine.test(str)
|
||||
}
|
||||
|
||||
function isRange(str) {
|
||||
return rangeLine.test(str);
|
||||
function isRange (str) {
|
||||
return rangeLine.test(str)
|
||||
}
|
||||
|
||||
function isVariable(str) {
|
||||
return variableLine.test(str);
|
||||
function isVariable (str) {
|
||||
return variableLine.test(str)
|
||||
}
|
||||
|
||||
function matchValue(str) {
|
||||
return value.exec(str);
|
||||
function matchValue (str) {
|
||||
return value.exec(str)
|
||||
}
|
||||
|
||||
function parseLiteral(str) {
|
||||
var res;
|
||||
if (res = str.match(numberLine)) {
|
||||
return Number(str);
|
||||
}
|
||||
if (res = str.match(boolLine)) {
|
||||
return str.toLowerCase() === 'true';
|
||||
}
|
||||
if (res = str.match(quotedLine)) {
|
||||
return str.slice(1, -1);
|
||||
}
|
||||
function parseLiteral (str) {
|
||||
var res = str.match(numberLine)
|
||||
if (res) {
|
||||
return Number(str)
|
||||
}
|
||||
res = str.match(boolLine)
|
||||
if (res) {
|
||||
return str.toLowerCase() === 'true'
|
||||
}
|
||||
res = str.match(quotedLine)
|
||||
if (res) {
|
||||
return str.slice(1, -1)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
quoted, number, bool, literal, filter, integer,
|
||||
hash, hashCapture,
|
||||
range, rangeCapture,
|
||||
identifier, value, quoteBalanced, operators,
|
||||
quotedLine, numberLine, boolLine, rangeLine, literalLine, filterLine, tagLine,
|
||||
isLiteral, isVariable, parseLiteral, isRange, matchValue, isInteger
|
||||
};
|
||||
quoted,
|
||||
number,
|
||||
bool,
|
||||
literal,
|
||||
filter,
|
||||
integer,
|
||||
hash,
|
||||
hashCapture,
|
||||
range,
|
||||
rangeCapture,
|
||||
identifier,
|
||||
value,
|
||||
quoteBalanced,
|
||||
operators,
|
||||
quotedLine,
|
||||
numberLine,
|
||||
boolLine,
|
||||
rangeLine,
|
||||
literalLine,
|
||||
filterLine,
|
||||
tagLine,
|
||||
isLiteral,
|
||||
isVariable,
|
||||
parseLiteral,
|
||||
isRange,
|
||||
matchValue,
|
||||
isInteger
|
||||
}
|
||||
|
||||
+15
-15
@@ -1,17 +1,17 @@
|
||||
var operators = {
|
||||
'==': (l, r) => l == r,
|
||||
'!=': (l, r) => l != r,
|
||||
'>': (l, r) => l !== null && r !== null && l > r,
|
||||
'<': (l, r) => l !== null && r !== null && l < r,
|
||||
'>=': (l, r) => l !== null && r !== null && l >= r,
|
||||
'<=': (l, r) => l !== null && r !== null && l <= r,
|
||||
'contains': (l, r) => {
|
||||
if (!l) return false;
|
||||
if (typeof l.indexOf !== 'function') return false;
|
||||
return l.indexOf(r) > -1;
|
||||
},
|
||||
'and': (l, r) => l && r,
|
||||
'or': (l, r) => l || r
|
||||
};
|
||||
'==': (l, r) => l === r,
|
||||
'!=': (l, r) => l !== r,
|
||||
'>': (l, r) => l !== null && r !== null && l > r,
|
||||
'<': (l, r) => l !== null && r !== null && l < r,
|
||||
'>=': (l, r) => l !== null && r !== null && l >= r,
|
||||
'<=': (l, r) => l !== null && r !== null && l <= r,
|
||||
'contains': (l, r) => {
|
||||
if (!l) return false
|
||||
if (typeof l.indexOf !== 'function') return false
|
||||
return l.indexOf(r) > -1
|
||||
},
|
||||
'and': (l, r) => l && r,
|
||||
'or': (l, r) => l || r
|
||||
}
|
||||
|
||||
module.exports = operators;
|
||||
module.exports = operators
|
||||
|
||||
+91
-91
@@ -1,105 +1,105 @@
|
||||
const lexical = require('./lexical.js');
|
||||
const ParseError = require('./util/error.js').ParseError;
|
||||
const assert = require('./util/assert.js');
|
||||
const lexical = require('./lexical.js')
|
||||
const ParseError = require('./util/error.js').ParseError
|
||||
const assert = require('./util/assert.js')
|
||||
|
||||
module.exports = function(Tag, Filter) {
|
||||
|
||||
var stream = {
|
||||
init: function(tokens) {
|
||||
this.tokens = tokens;
|
||||
this.handlers = {};
|
||||
return this;
|
||||
},
|
||||
on: function(name, cb) {
|
||||
this.handlers[name] = cb;
|
||||
return this;
|
||||
},
|
||||
trigger: function(event, arg) {
|
||||
var h = this.handlers[event];
|
||||
if (typeof h === 'function') {
|
||||
h(arg);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
start: function() {
|
||||
this.trigger('start');
|
||||
var token;
|
||||
while (!this.stopRequested && (token = this.tokens.shift())) {
|
||||
if (this.trigger('token', token)) continue;
|
||||
if (token.type == 'tag' &&
|
||||
this.trigger(`tag:${token.name}`, token)) {
|
||||
continue;
|
||||
}
|
||||
var template = parseToken(token, this.tokens);
|
||||
this.trigger('template', template);
|
||||
}
|
||||
if (!this.stopRequested) this.trigger('end');
|
||||
return this;
|
||||
},
|
||||
stop: function() {
|
||||
this.stopRequested = true;
|
||||
return this;
|
||||
module.exports = function (Tag, Filter) {
|
||||
var stream = {
|
||||
init: function (tokens) {
|
||||
this.tokens = tokens
|
||||
this.handlers = {}
|
||||
return this
|
||||
},
|
||||
on: function (name, cb) {
|
||||
this.handlers[name] = cb
|
||||
return this
|
||||
},
|
||||
trigger: function (event, arg) {
|
||||
var h = this.handlers[event]
|
||||
if (typeof h === 'function') {
|
||||
h(arg)
|
||||
return true
|
||||
}
|
||||
},
|
||||
start: function () {
|
||||
this.trigger('start')
|
||||
var token
|
||||
while (!this.stopRequested && (token = this.tokens.shift())) {
|
||||
if (this.trigger('token', token)) continue
|
||||
if (token.type === 'tag' &&
|
||||
this.trigger(`tag:${token.name}`, token)) {
|
||||
continue
|
||||
}
|
||||
};
|
||||
|
||||
function parse(tokens) {
|
||||
var token, templates = [];
|
||||
while (token = tokens.shift()) {
|
||||
templates.push(parseToken(token, tokens));
|
||||
}
|
||||
return templates;
|
||||
var template = parseToken(token, this.tokens)
|
||||
this.trigger('template', template)
|
||||
}
|
||||
if (!this.stopRequested) this.trigger('end')
|
||||
return this
|
||||
},
|
||||
stop: function () {
|
||||
this.stopRequested = true
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
function parseToken(token, tokens) {
|
||||
try {
|
||||
var tpl = null;
|
||||
if (token.type === 'tag') {
|
||||
tpl = parseTag(token, tokens);
|
||||
} else if (token.type === 'output') {
|
||||
tpl = parseOutput(token.value);
|
||||
} else { // token.type === 'html'
|
||||
tpl = token;
|
||||
}
|
||||
tpl.token = token;
|
||||
return tpl;
|
||||
} catch (e) {
|
||||
throw new ParseError(e, token);
|
||||
}
|
||||
function parse (tokens) {
|
||||
var token
|
||||
var templates = []
|
||||
while ((token = tokens.shift())) {
|
||||
templates.push(parseToken(token, tokens))
|
||||
}
|
||||
return templates
|
||||
}
|
||||
|
||||
function parseTag(token, tokens) {
|
||||
if (token.name === 'continue' || token.name === 'break') return token;
|
||||
return Tag.construct(token, tokens);
|
||||
function parseToken (token, tokens) {
|
||||
try {
|
||||
var tpl = null
|
||||
if (token.type === 'tag') {
|
||||
tpl = parseTag(token, tokens)
|
||||
} else if (token.type === 'output') {
|
||||
tpl = parseOutput(token.value)
|
||||
} else { // token.type === 'html'
|
||||
tpl = token
|
||||
}
|
||||
tpl.token = token
|
||||
return tpl
|
||||
} catch (e) {
|
||||
throw new ParseError(e, token)
|
||||
}
|
||||
}
|
||||
|
||||
function parseOutput(str) {
|
||||
var match = lexical.matchValue(str);
|
||||
assert(match, `illegal output string: ${str}`);
|
||||
function parseTag (token, tokens) {
|
||||
if (token.name === 'continue' || token.name === 'break') return token
|
||||
return Tag.construct(token, tokens)
|
||||
}
|
||||
|
||||
var initial = match[0];
|
||||
str = str.substr(match.index + match[0].length);
|
||||
function parseOutput (str) {
|
||||
var match = lexical.matchValue(str)
|
||||
assert(match, `illegal output string: ${str}`)
|
||||
|
||||
var filters = [];
|
||||
while (match = lexical.filter.exec(str)) {
|
||||
filters.push([match[0].trim()]);
|
||||
}
|
||||
var initial = match[0]
|
||||
str = str.substr(match.index + match[0].length)
|
||||
|
||||
return {
|
||||
type: 'output',
|
||||
initial: initial,
|
||||
filters: filters.map(str => Filter.construct(str))
|
||||
};
|
||||
}
|
||||
|
||||
function parseStream(tokens) {
|
||||
var s = Object.create(stream);
|
||||
return s.init(tokens);
|
||||
var filters = []
|
||||
while ((match = lexical.filter.exec(str))) {
|
||||
filters.push([match[0].trim()])
|
||||
}
|
||||
|
||||
return {
|
||||
parse,
|
||||
parseTag,
|
||||
parseStream,
|
||||
parseOutput
|
||||
};
|
||||
};
|
||||
type: 'output',
|
||||
initial: initial,
|
||||
filters: filters.map(str => Filter.construct(str))
|
||||
}
|
||||
}
|
||||
|
||||
function parseStream (tokens) {
|
||||
var s = Object.create(stream)
|
||||
return s.init(tokens)
|
||||
}
|
||||
|
||||
return {
|
||||
parse,
|
||||
parseTag,
|
||||
parseStream,
|
||||
parseOutput
|
||||
}
|
||||
}
|
||||
|
||||
+56
-56
@@ -1,68 +1,68 @@
|
||||
const Syntax = require('./syntax.js');
|
||||
const Promise = require('any-promise');
|
||||
const mapSeries = require('./util/promise.js').mapSeries;
|
||||
const RenderBreakError = require('./util/error.js').RenderBreakError;
|
||||
const RenderError = require('./util/error.js').RenderError;
|
||||
const assert = require('./util/assert.js');
|
||||
const Syntax = require('./syntax.js')
|
||||
const Promise = require('any-promise')
|
||||
const mapSeries = require('./util/promise.js').mapSeries
|
||||
const RenderBreakError = require('./util/error.js').RenderBreakError
|
||||
const RenderError = require('./util/error.js').RenderError
|
||||
const assert = require('./util/assert.js')
|
||||
|
||||
var render = {
|
||||
|
||||
renderTemplates: function(templates, scope) {
|
||||
assert(scope, 'unable to evalTemplates: scope undefined');
|
||||
renderTemplates: function (templates, scope) {
|
||||
assert(scope, 'unable to evalTemplates: scope undefined')
|
||||
|
||||
var html = '';
|
||||
return mapSeries(templates, (tpl) => {
|
||||
return renderTemplate.call(this, tpl)
|
||||
.then(partial => html += partial)
|
||||
.catch(e => {
|
||||
if (e instanceof RenderBreakError) {
|
||||
e.resolvedHTML = html;
|
||||
throw e;
|
||||
}
|
||||
throw new RenderError(e, tpl);
|
||||
});
|
||||
}).then(() => html);
|
||||
var html = ''
|
||||
return mapSeries(templates, (tpl) => {
|
||||
return renderTemplate.call(this, tpl)
|
||||
.then(partial => (html += partial))
|
||||
.catch(e => {
|
||||
if (e instanceof RenderBreakError) {
|
||||
e.resolvedHTML = html
|
||||
throw e
|
||||
}
|
||||
throw new RenderError(e, tpl)
|
||||
})
|
||||
}).then(() => html)
|
||||
|
||||
function renderTemplate(template) {
|
||||
if (template.type === 'tag') {
|
||||
return this.renderTag(template, scope)
|
||||
.then(partial => partial === undefined ? '' : partial);
|
||||
} else if (template.type === 'output') {
|
||||
return Promise.resolve()
|
||||
function renderTemplate (template) {
|
||||
if (template.type === 'tag') {
|
||||
return this.renderTag(template, scope)
|
||||
.then(partial => partial === undefined ? '' : partial)
|
||||
} else if (template.type === 'output') {
|
||||
return Promise.resolve()
|
||||
.then(() => this.evalOutput(template, scope))
|
||||
.then(partial => partial === undefined ? '' : stringify(partial));
|
||||
} else { // template.type === 'html'
|
||||
return Promise.resolve(template.value);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
renderTag: function(template, scope) {
|
||||
if (template.name === 'continue') {
|
||||
return Promise.reject(new RenderBreakError('continue'));
|
||||
}
|
||||
if (template.name === 'break') {
|
||||
return Promise.reject(new RenderBreakError('break'));
|
||||
}
|
||||
return template.render(scope);
|
||||
},
|
||||
|
||||
evalOutput: function(template, scope) {
|
||||
assert(scope, 'unable to evalOutput: scope undefined');
|
||||
return template.filters.reduce(
|
||||
(prev, filter) => filter.render(prev, scope),
|
||||
Syntax.evalExp(template.initial, scope));
|
||||
.then(partial => partial === undefined ? '' : stringify(partial))
|
||||
} else { // template.type === 'html'
|
||||
return Promise.resolve(template.value)
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
function factory() {
|
||||
var instance = Object.create(render);
|
||||
return instance;
|
||||
renderTag: function (template, scope) {
|
||||
if (template.name === 'continue') {
|
||||
return Promise.reject(new RenderBreakError('continue'))
|
||||
}
|
||||
if (template.name === 'break') {
|
||||
return Promise.reject(new RenderBreakError('break'))
|
||||
}
|
||||
return template.render(scope)
|
||||
},
|
||||
|
||||
evalOutput: function (template, scope) {
|
||||
assert(scope, 'unable to evalOutput: scope undefined')
|
||||
return template.filters.reduce(
|
||||
(prev, filter) => filter.render(prev, scope),
|
||||
Syntax.evalExp(template.initial, scope))
|
||||
}
|
||||
}
|
||||
|
||||
function stringify(val) {
|
||||
if (typeof val === 'string') return val;
|
||||
return JSON.stringify(val);
|
||||
function factory () {
|
||||
var instance = Object.create(render)
|
||||
return instance
|
||||
}
|
||||
|
||||
module.exports = factory;
|
||||
function stringify (val) {
|
||||
if (typeof val === 'string') return val
|
||||
return JSON.stringify(val)
|
||||
}
|
||||
|
||||
module.exports = factory
|
||||
|
||||
+165
-169
@@ -1,182 +1,178 @@
|
||||
const _ = require('./util/underscore.js');
|
||||
const lexical = require('./lexical.js');
|
||||
const assert = require('./util/assert.js');
|
||||
const toStr = Object.prototype.toString;
|
||||
const _ = require('./util/underscore.js')
|
||||
const lexical = require('./lexical.js')
|
||||
const assert = require('./util/assert.js')
|
||||
const toStr = Object.prototype.toString
|
||||
|
||||
var Scope = {
|
||||
getAll: function() {
|
||||
var ctx = {};
|
||||
for (var i = this.scopes.length - 1; i >= 0; i--) {
|
||||
_.assign(ctx, this.scopes[i]);
|
||||
getAll: function () {
|
||||
var ctx = {}
|
||||
for (var i = this.scopes.length - 1; i >= 0; i--) {
|
||||
_.assign(ctx, this.scopes[i])
|
||||
}
|
||||
return ctx
|
||||
},
|
||||
get: function (str) {
|
||||
for (var i = this.scopes.length - 1; i >= 0; i--) {
|
||||
try {
|
||||
return this.getPropertyByPath(this.scopes[i], str)
|
||||
} catch (e) {
|
||||
if (/undefined variable/.test(e.message)) {
|
||||
continue
|
||||
}
|
||||
return ctx;
|
||||
},
|
||||
get: function(str) {
|
||||
for (var i = this.scopes.length - 1; i >= 0; i--) {
|
||||
try {
|
||||
return this.getPropertyByPath(this.scopes[i], str);
|
||||
} catch (e) {
|
||||
if (/undefined variable/.test(e.message)) {
|
||||
continue;
|
||||
}
|
||||
if (/Cannot read property/.test(e.message)) {
|
||||
if (this.opts.strict_variables) {
|
||||
e.message += ': ' + str;
|
||||
throw e;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
e.message += ': ' + str;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
if (/Cannot read property/.test(e.message)) {
|
||||
if (this.opts.strict_variables) {
|
||||
e.message += ': ' + str
|
||||
throw e
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
e.message += ': ' + str
|
||||
throw e
|
||||
}
|
||||
if (this.opts.strict_variables) {
|
||||
throw new TypeError('undefined variable: ' + str);
|
||||
}
|
||||
}
|
||||
if (this.opts.strict_variables) {
|
||||
throw new TypeError('undefined variable: ' + str)
|
||||
}
|
||||
},
|
||||
set: function (k, v) {
|
||||
this.setPropertyByPath(this.scopes[this.scopes.length - 1], k, v)
|
||||
return this
|
||||
},
|
||||
push: function (ctx) {
|
||||
assert(ctx, `trying to push ${ctx} into scopes`)
|
||||
return this.scopes.push(ctx)
|
||||
},
|
||||
pop: function () {
|
||||
return this.scopes.pop()
|
||||
},
|
||||
unshift: function (ctx) {
|
||||
assert(ctx, `trying to push ${ctx} into scopes`)
|
||||
return this.scopes.unshift(ctx)
|
||||
},
|
||||
shift: function () {
|
||||
return this.scopes.shift()
|
||||
},
|
||||
setPropertyByPath: function (obj, path, val) {
|
||||
if (_.isString(path)) {
|
||||
var paths = path.replace(/\[/g, '.').replace(/\]/g, '').split('.')
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
var key = paths[i]
|
||||
if (i === paths.length - 1) {
|
||||
return (obj[key] = val)
|
||||
}
|
||||
},
|
||||
set: function(k, v) {
|
||||
this.setPropertyByPath(this.scopes[this.scopes.length - 1], k, v);
|
||||
return this;
|
||||
},
|
||||
push: function(ctx) {
|
||||
assert(ctx, `trying to push ${ctx} into scopes`);
|
||||
return this.scopes.push(ctx);
|
||||
},
|
||||
pop: function() {
|
||||
return this.scopes.pop();
|
||||
},
|
||||
unshift: function(ctx) {
|
||||
assert(ctx, `trying to push ${ctx} into scopes`);
|
||||
return this.scopes.unshift(ctx);
|
||||
},
|
||||
shift: function() {
|
||||
return this.scopes.shift();
|
||||
},
|
||||
setPropertyByPath: function(obj, path, val) {
|
||||
if (_.isString(path)) {
|
||||
var paths = path.replace(/\[/g, '.').replace(/\]/g, '').split('.');
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
var key = paths[i];
|
||||
if (i === paths.length - 1) {
|
||||
return obj[key] = val;
|
||||
}
|
||||
if (undefined === obj[key]) obj[key] = {};
|
||||
if (undefined === obj[key]) obj[key] = {}
|
||||
// case for readonly objects
|
||||
obj = obj[key] || {};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getPropertyByPath: function(obj, path) {
|
||||
var paths = this.propertyAccessSeq(path + '');
|
||||
var varName = paths.shift();
|
||||
if (!obj.hasOwnProperty(varName)) {
|
||||
throw new TypeError('undefined variable');
|
||||
}
|
||||
var variable = obj[varName];
|
||||
var lastName = paths.pop();
|
||||
paths.forEach(p => variable = variable[p]);
|
||||
if (undefined !== lastName) {
|
||||
if (lastName === 'size' &&
|
||||
(toStr.call(variable) === '[object Array]'
|
||||
|| toStr.call(variable) === '[object String]')) {
|
||||
return variable.length;
|
||||
}
|
||||
variable = variable[lastName]
|
||||
}
|
||||
return variable;
|
||||
},
|
||||
|
||||
/*
|
||||
* Parse property access sequence from access string
|
||||
* @example
|
||||
* accessSeq("foo.bar") // ['foo', 'bar']
|
||||
* accessSeq("foo['bar']") // ['foo', 'bar']
|
||||
* accessSeq("foo['b]r']") // ['foo', 'b]r']
|
||||
* accessSeq("foo[bar.coo]") // ['foo', 'bar'], for bar.coo == 'bar'
|
||||
*/
|
||||
propertyAccessSeq: function(str) {
|
||||
var seq = [],
|
||||
name = '';
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
if (str[i] === '[') {
|
||||
seq.push(name);
|
||||
name = '';
|
||||
|
||||
var delemiter = str[i + 1];
|
||||
// foo[bar.coo]
|
||||
if (delemiter !== "'" && delemiter !== '"') {
|
||||
var j = matchRightBracket(str, i + 1);
|
||||
assert(j !== -1, `unbalanced []: ${str}`);
|
||||
name = str.slice(i + 1, j);
|
||||
// foo[1]
|
||||
if (lexical.isInteger(name)) {
|
||||
seq.push(name);
|
||||
}
|
||||
// foo["bar"]
|
||||
else {
|
||||
seq.push(this.get(name));
|
||||
}
|
||||
name = '';
|
||||
i = j;
|
||||
}
|
||||
// foo["bar"]
|
||||
else {
|
||||
j = str.indexOf(delemiter, i + 2);
|
||||
assert(j !== -1, `unbalanced ${delemiter}: ${str}`);
|
||||
name = str.slice(i + 2, j);
|
||||
seq.push(name);
|
||||
name = '';
|
||||
i = j + 2;
|
||||
}
|
||||
}
|
||||
// foo.bar
|
||||
else if (str[i] === ".") {
|
||||
seq.push(name);
|
||||
name = '';
|
||||
}
|
||||
//foo.bar
|
||||
else {
|
||||
name += str[i];
|
||||
}
|
||||
}
|
||||
if (name.length) seq.push(name);
|
||||
return seq;
|
||||
obj = obj[key] || {}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
function matchRightBracket(str, begin) {
|
||||
var stack = 1; // count of '[' - count of ']'
|
||||
for (var i = begin; i < str.length; i++) {
|
||||
if (str[i] === '[') {
|
||||
stack++;
|
||||
}
|
||||
if (str[i] === ']') {
|
||||
stack--;
|
||||
if (stack === 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
getPropertyByPath: function (obj, path) {
|
||||
var paths = this.propertyAccessSeq(path + '')
|
||||
var varName = paths.shift()
|
||||
if (!obj.hasOwnProperty(varName)) {
|
||||
throw new TypeError('undefined variable')
|
||||
}
|
||||
return -1;
|
||||
var variable = obj[varName]
|
||||
var lastName = paths.pop()
|
||||
paths.forEach(p => (variable = variable[p]))
|
||||
if (undefined !== lastName) {
|
||||
if (lastName === 'size' &&
|
||||
(toStr.call(variable) === '[object Array]' ||
|
||||
toStr.call(variable) === '[object String]')) {
|
||||
return variable.length
|
||||
}
|
||||
variable = variable[lastName]
|
||||
}
|
||||
return variable
|
||||
},
|
||||
|
||||
/*
|
||||
* Parse property access sequence from access string
|
||||
* @example
|
||||
* accessSeq("foo.bar") // ['foo', 'bar']
|
||||
* accessSeq("foo['bar']") // ['foo', 'bar']
|
||||
* accessSeq("foo['b]r']") // ['foo', 'b]r']
|
||||
* accessSeq("foo[bar.coo]") // ['foo', 'bar'], for bar.coo == 'bar'
|
||||
*/
|
||||
propertyAccessSeq: function (str) {
|
||||
var seq = []
|
||||
var name = ''
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
if (str[i] === '[') {
|
||||
seq.push(name)
|
||||
name = ''
|
||||
|
||||
var delemiter = str[i + 1]
|
||||
if (delemiter !== "'" && delemiter !== '"') {
|
||||
// foo[bar.coo]
|
||||
var j = matchRightBracket(str, i + 1)
|
||||
assert(j !== -1, `unbalanced []: ${str}`)
|
||||
name = str.slice(i + 1, j)
|
||||
if (lexical.isInteger(name)) {
|
||||
// foo[1]
|
||||
seq.push(name)
|
||||
} else {
|
||||
// foo["bar"]
|
||||
seq.push(this.get(name))
|
||||
}
|
||||
name = ''
|
||||
i = j
|
||||
} else {
|
||||
// foo["bar"]
|
||||
j = str.indexOf(delemiter, i + 2)
|
||||
assert(j !== -1, `unbalanced ${delemiter}: ${str}`)
|
||||
name = str.slice(i + 2, j)
|
||||
seq.push(name)
|
||||
name = ''
|
||||
i = j + 2
|
||||
}
|
||||
} else if (str[i] === '.') {
|
||||
// foo.bar
|
||||
seq.push(name)
|
||||
name = ''
|
||||
} else {
|
||||
// foo.bar
|
||||
name += str[i]
|
||||
}
|
||||
}
|
||||
if (name.length) seq.push(name)
|
||||
return seq
|
||||
}
|
||||
}
|
||||
|
||||
exports.factory = function(ctx, opts) {
|
||||
opts = _.assign({
|
||||
strict_variables: false,
|
||||
strict_filters: false,
|
||||
blocks: {},
|
||||
root: []
|
||||
}, opts);
|
||||
function matchRightBracket (str, begin) {
|
||||
var stack = 1 // count of '[' - count of ']'
|
||||
for (var i = begin; i < str.length; i++) {
|
||||
if (str[i] === '[') {
|
||||
stack++
|
||||
}
|
||||
if (str[i] === ']') {
|
||||
stack--
|
||||
if (stack === 0) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
ctx = _.assign(ctx, {
|
||||
liquid: opts
|
||||
});
|
||||
exports.factory = function (ctx, opts) {
|
||||
opts = _.assign({
|
||||
strict_variables: false,
|
||||
strict_filters: false,
|
||||
blocks: {},
|
||||
root: []
|
||||
}, opts)
|
||||
|
||||
var scope = Object.create(Scope);
|
||||
scope.opts = opts;
|
||||
scope.scopes = [ctx];
|
||||
return scope;
|
||||
};
|
||||
ctx = _.assign(ctx, {
|
||||
liquid: opts
|
||||
})
|
||||
|
||||
var scope = Object.create(Scope)
|
||||
scope.opts = opts
|
||||
scope.scopes = [ctx]
|
||||
return scope
|
||||
}
|
||||
|
||||
+40
-40
@@ -1,55 +1,55 @@
|
||||
const operators = require('./operators.js');
|
||||
const lexical = require('./lexical.js');
|
||||
const assert = require('../src/util/assert.js');
|
||||
const operators = require('./operators.js')
|
||||
const lexical = require('./lexical.js')
|
||||
const assert = require('../src/util/assert.js')
|
||||
|
||||
function evalExp(exp, scope) {
|
||||
assert(scope, 'unable to evalExp: scope undefined');
|
||||
var operatorREs = lexical.operators,
|
||||
match;
|
||||
for (var i = 0; i < operatorREs.length; i++) {
|
||||
var operatorRE = operatorREs[i];
|
||||
var expRE = new RegExp(`^(${lexical.quoteBalanced.source})(${operatorRE.source})(${lexical.quoteBalanced.source})$`);
|
||||
if (match = exp.match(expRE)) {
|
||||
var l = evalExp(match[1], scope);
|
||||
var op = operators[match[2].trim()];
|
||||
var r = evalExp(match[3], scope);
|
||||
return op(l, r);
|
||||
}
|
||||
function evalExp (exp, scope) {
|
||||
assert(scope, 'unable to evalExp: scope undefined')
|
||||
var operatorREs = lexical.operators
|
||||
var match
|
||||
for (var i = 0; i < operatorREs.length; i++) {
|
||||
var operatorRE = operatorREs[i]
|
||||
var expRE = new RegExp(`^(${lexical.quoteBalanced.source})(${operatorRE.source})(${lexical.quoteBalanced.source})$`)
|
||||
if ((match = exp.match(expRE))) {
|
||||
var l = evalExp(match[1], scope)
|
||||
var op = operators[match[2].trim()]
|
||||
var r = evalExp(match[3], scope)
|
||||
return op(l, r)
|
||||
}
|
||||
}
|
||||
|
||||
if (match = exp.match(lexical.rangeLine)) {
|
||||
var low = evalValue(match[1], scope),
|
||||
high = evalValue(match[2], scope);
|
||||
var range = [];
|
||||
for (var j = low; j <= high; j++) {
|
||||
range.push(j);
|
||||
}
|
||||
return range;
|
||||
if ((match = exp.match(lexical.rangeLine))) {
|
||||
var low = evalValue(match[1], scope)
|
||||
var high = evalValue(match[2], scope)
|
||||
var range = []
|
||||
for (var j = low; j <= high; j++) {
|
||||
range.push(j)
|
||||
}
|
||||
return range
|
||||
}
|
||||
|
||||
return evalValue(exp, scope);
|
||||
return evalValue(exp, scope)
|
||||
}
|
||||
|
||||
function evalValue(str, scope) {
|
||||
str = str && str.trim();
|
||||
if (!str) return undefined;
|
||||
function evalValue (str, scope) {
|
||||
str = str && str.trim()
|
||||
if (!str) return undefined
|
||||
|
||||
if (lexical.isLiteral(str)) {
|
||||
return lexical.parseLiteral(str);
|
||||
}
|
||||
if (lexical.isVariable(str)) {
|
||||
return scope.get(str);
|
||||
}
|
||||
if (lexical.isLiteral(str)) {
|
||||
return lexical.parseLiteral(str)
|
||||
}
|
||||
if (lexical.isVariable(str)) {
|
||||
return scope.get(str)
|
||||
}
|
||||
}
|
||||
|
||||
function isTruthy(val) {
|
||||
return !isFalsy(val);
|
||||
function isTruthy (val) {
|
||||
return !isFalsy(val)
|
||||
}
|
||||
|
||||
function isFalsy(val) {
|
||||
return false === val || undefined === val || null === val;;
|
||||
function isFalsy (val) {
|
||||
return val === false || undefined === val || val === null
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
evalExp, evalValue, isTruthy, isFalsy
|
||||
};
|
||||
evalExp, evalValue, isTruthy, isFalsy
|
||||
}
|
||||
|
||||
+64
-64
@@ -1,73 +1,73 @@
|
||||
const lexical = require('./lexical.js');
|
||||
const _ = require('./util/underscore.js');
|
||||
const Promise = require('any-promise');
|
||||
const Syntax = require('./syntax.js');
|
||||
const assert = require('./util/assert.js');
|
||||
const lexical = require('./lexical.js')
|
||||
const _ = require('./util/underscore.js')
|
||||
const Promise = require('any-promise')
|
||||
const Syntax = require('./syntax.js')
|
||||
const assert = require('./util/assert.js')
|
||||
|
||||
function hash(markup, scope) {
|
||||
var obj = {},
|
||||
match;
|
||||
lexical.hashCapture.lastIndex = 0;
|
||||
while (match = lexical.hashCapture.exec(markup)) {
|
||||
var k = match[1],
|
||||
v = match[2];
|
||||
obj[k] = Syntax.evalValue(v, scope);
|
||||
}
|
||||
return obj;
|
||||
function hash (markup, scope) {
|
||||
var obj = {}
|
||||
var match
|
||||
lexical.hashCapture.lastIndex = 0
|
||||
while ((match = lexical.hashCapture.exec(markup))) {
|
||||
var k = match[1]
|
||||
var v = match[2]
|
||||
obj[k] = Syntax.evalValue(v, scope)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
module.exports = function() {
|
||||
var tagImpls = {};
|
||||
module.exports = function () {
|
||||
var tagImpls = {}
|
||||
|
||||
var _tagInstance = {
|
||||
render: function(scope) {
|
||||
var obj = hash(this.token.args, scope);
|
||||
var impl = this.tagImpl;
|
||||
if (typeof impl.render !== 'function') {
|
||||
return Promise.resolve('');
|
||||
}
|
||||
return Promise.resolve()
|
||||
.then(() => typeof impl.render === 'function' ?
|
||||
impl.render(scope, obj) : '')
|
||||
.catch(function(e) {
|
||||
if (_.isError(e)) {
|
||||
throw e;
|
||||
}
|
||||
var msg = `Please reject with an Error in ${impl.render}, got ${e}`;
|
||||
throw new Error(msg);
|
||||
});
|
||||
},
|
||||
parse: function(token, tokens) {
|
||||
this.type = 'tag';
|
||||
this.token = token;
|
||||
this.name = token.name;
|
||||
var _tagInstance = {
|
||||
render: function (scope) {
|
||||
var obj = hash(this.token.args, scope)
|
||||
var impl = this.tagImpl
|
||||
if (typeof impl.render !== 'function') {
|
||||
return Promise.resolve('')
|
||||
}
|
||||
return Promise.resolve()
|
||||
.then(() => typeof impl.render === 'function'
|
||||
? impl.render(scope, obj) : '')
|
||||
.catch(function (e) {
|
||||
if (_.isError(e)) {
|
||||
throw e
|
||||
}
|
||||
var msg = `Please reject with an Error in ${impl.render}, got ${e}`
|
||||
throw new Error(msg)
|
||||
})
|
||||
},
|
||||
parse: function (token, tokens) {
|
||||
this.type = 'tag'
|
||||
this.token = token
|
||||
this.name = token.name
|
||||
|
||||
var tagImpl = tagImpls[this.name];
|
||||
assert(tagImpl, `tag ${this.name} not found`);
|
||||
this.tagImpl = Object.create(tagImpl);
|
||||
if (this.tagImpl.parse) {
|
||||
this.tagImpl.parse(token, tokens);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function register(name, tag) {
|
||||
tagImpls[name] = tag;
|
||||
var tagImpl = tagImpls[this.name]
|
||||
assert(tagImpl, `tag ${this.name} not found`)
|
||||
this.tagImpl = Object.create(tagImpl)
|
||||
if (this.tagImpl.parse) {
|
||||
this.tagImpl.parse(token, tokens)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function construct(token, tokens) {
|
||||
var instance = Object.create(_tagInstance);
|
||||
instance.parse(token, tokens);
|
||||
return instance;
|
||||
}
|
||||
function register (name, tag) {
|
||||
tagImpls[name] = tag
|
||||
}
|
||||
|
||||
function clear() {
|
||||
tagImpls = {};
|
||||
}
|
||||
function construct (token, tokens) {
|
||||
var instance = Object.create(_tagInstance)
|
||||
instance.parse(token, tokens)
|
||||
return instance
|
||||
}
|
||||
|
||||
return {
|
||||
construct,
|
||||
register,
|
||||
clear
|
||||
};
|
||||
};
|
||||
function clear () {
|
||||
tagImpls = {}
|
||||
}
|
||||
|
||||
return {
|
||||
construct,
|
||||
register,
|
||||
clear
|
||||
}
|
||||
}
|
||||
|
||||
+77
-77
@@ -1,92 +1,92 @@
|
||||
const lexical = require('./lexical.js');
|
||||
const TokenizationError = require('./util/error.js').TokenizationError;
|
||||
const _ = require('./util/underscore.js');
|
||||
const assert = require('../src/util/assert.js');
|
||||
const lexical = require('./lexical.js')
|
||||
const TokenizationError = require('./util/error.js').TokenizationError
|
||||
const _ = require('./util/underscore.js')
|
||||
const assert = require('../src/util/assert.js')
|
||||
|
||||
function parse(html, filepath, options) {
|
||||
assert(_.isString(html), 'illegal input type');
|
||||
function parse (html, filepath, options) {
|
||||
assert(_.isString(html), 'illegal input type')
|
||||
|
||||
html = whiteSpaceCtrl(html, options);
|
||||
html = whiteSpaceCtrl(html, options)
|
||||
|
||||
var tokens = [];
|
||||
var syntax = /({%-?([\s\S]*?)-?%})|({{([\s\S]*?)}})/g;
|
||||
var result, htmlFragment, token;
|
||||
var lastMatchEnd = 0, lastMatchBegin = -1, parsedLinesCount = 0;
|
||||
var tokens = []
|
||||
var syntax = /({%-?([\s\S]*?)-?%})|({{([\s\S]*?)}})/g
|
||||
var result, htmlFragment, token
|
||||
var lastMatchEnd = 0
|
||||
var lastMatchBegin = -1
|
||||
var parsedLinesCount = 0
|
||||
|
||||
while ((result = syntax.exec(html)) !== null) {
|
||||
while ((result = syntax.exec(html)) !== null) {
|
||||
// passed html fragments
|
||||
if (result.index > lastMatchEnd) {
|
||||
htmlFragment = html.slice(lastMatchEnd, result.index);
|
||||
tokens.push({
|
||||
type: 'html',
|
||||
raw: htmlFragment,
|
||||
value: htmlFragment
|
||||
});
|
||||
}
|
||||
// tag appeared
|
||||
if (result[1]) {
|
||||
token = factory('tag', 1, result);
|
||||
|
||||
var match = token.value.match(lexical.tagLine);
|
||||
if (!match) {
|
||||
throw new TokenizationError(`illegal tag syntax`, token);
|
||||
}
|
||||
token.name = match[1];
|
||||
token.args = match[2];
|
||||
|
||||
tokens.push(token);
|
||||
}
|
||||
// output
|
||||
else { token = factory('output', 3, result);
|
||||
tokens.push(token);
|
||||
}
|
||||
lastMatchEnd = syntax.lastIndex;
|
||||
if (result.index > lastMatchEnd) {
|
||||
htmlFragment = html.slice(lastMatchEnd, result.index)
|
||||
tokens.push({
|
||||
type: 'html',
|
||||
raw: htmlFragment,
|
||||
value: htmlFragment
|
||||
})
|
||||
}
|
||||
if (result[1]) {
|
||||
// tag appeared
|
||||
token = factory('tag', 1, result)
|
||||
|
||||
var match = token.value.match(lexical.tagLine)
|
||||
if (!match) {
|
||||
throw new TokenizationError(`illegal tag syntax`, token)
|
||||
}
|
||||
token.name = match[1]
|
||||
token.args = match[2]
|
||||
|
||||
tokens.push(token)
|
||||
} else {
|
||||
// output
|
||||
token = factory('output', 3, result)
|
||||
tokens.push(token)
|
||||
}
|
||||
lastMatchEnd = syntax.lastIndex
|
||||
}
|
||||
|
||||
// remaining html
|
||||
if (html.length > lastMatchEnd) {
|
||||
htmlFragment = html.slice(lastMatchEnd, html.length);
|
||||
tokens.push({
|
||||
type: 'html',
|
||||
raw: htmlFragment,
|
||||
value: htmlFragment
|
||||
});
|
||||
}
|
||||
return tokens;
|
||||
if (html.length > lastMatchEnd) {
|
||||
htmlFragment = html.slice(lastMatchEnd, html.length)
|
||||
tokens.push({
|
||||
type: 'html',
|
||||
raw: htmlFragment,
|
||||
value: htmlFragment
|
||||
})
|
||||
}
|
||||
return tokens
|
||||
|
||||
function factory(type, offset, match) {
|
||||
return {
|
||||
type: type,
|
||||
raw: match[offset],
|
||||
value: match[offset + 1].trim(),
|
||||
line: getLineNum(match),
|
||||
input: html,
|
||||
file: filepath
|
||||
};
|
||||
function factory (type, offset, match) {
|
||||
return {
|
||||
type: type,
|
||||
raw: match[offset],
|
||||
value: match[offset + 1].trim(),
|
||||
line: getLineNum(match),
|
||||
input: html,
|
||||
file: filepath
|
||||
}
|
||||
}
|
||||
|
||||
function getLineNum(match) {
|
||||
var lines = match.input.slice(lastMatchBegin + 1, match.index).split('\n');
|
||||
parsedLinesCount += lines.length - 1;
|
||||
lastMatchBegin = match.index;
|
||||
return parsedLinesCount + 1;
|
||||
}
|
||||
function getLineNum (match) {
|
||||
var lines = match.input.slice(lastMatchBegin + 1, match.index).split('\n')
|
||||
parsedLinesCount += lines.length - 1
|
||||
lastMatchBegin = match.index
|
||||
return parsedLinesCount + 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function whiteSpaceCtrl(html, options){
|
||||
options = options || {};
|
||||
if(options.trim_left) {
|
||||
html = html.replace(/{%-?/g, '{%-');
|
||||
}
|
||||
if(options.trim_right) {
|
||||
html = html.replace(/-?%}/g, '-%}');
|
||||
}
|
||||
var rLeft = options.greedy ? /\s+({%-)/g : /[\t\r ]*({%-)/g;
|
||||
var rRight = options.greedy ? /(-%})\s+/g : /(-%})[\t\r ]*\n?/g;
|
||||
return html.replace(rLeft, '$1').replace(rRight, '$1');
|
||||
function whiteSpaceCtrl (html, options) {
|
||||
options = options || {}
|
||||
if (options.trim_left) {
|
||||
html = html.replace(/{%-?/g, '{%-')
|
||||
}
|
||||
if (options.trim_right) {
|
||||
html = html.replace(/-?%}/g, '-%}')
|
||||
}
|
||||
var rLeft = options.greedy ? /\s+({%-)/g : /[\t\r ]*({%-)/g
|
||||
var rRight = options.greedy ? /(-%})\s+/g : /(-%})[\t\r ]*\n?/g
|
||||
return html.replace(rLeft, '$1').replace(rRight, '$1')
|
||||
}
|
||||
|
||||
exports.parse = parse;
|
||||
exports.whiteSpaceCtrl = whiteSpaceCtrl;
|
||||
exports.parse = parse
|
||||
exports.whiteSpaceCtrl = whiteSpaceCtrl
|
||||
|
||||
+9
-9
@@ -1,13 +1,13 @@
|
||||
const AssertionError = require('./error.js').AssertionError;
|
||||
const AssertionError = require('./error.js').AssertionError
|
||||
|
||||
function assert(predicate, message) {
|
||||
if (!predicate) {
|
||||
if (message instanceof Error) {
|
||||
throw message;
|
||||
}
|
||||
var message = message || `expect ${predicate} to be true`;
|
||||
throw new AssertionError(message);
|
||||
function assert (predicate, message) {
|
||||
if (!predicate) {
|
||||
if (message instanceof Error) {
|
||||
throw message
|
||||
}
|
||||
message = message || `expect ${predicate} to be true`
|
||||
throw new AssertionError(message)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = assert;
|
||||
module.exports = assert
|
||||
|
||||
+88
-88
@@ -1,118 +1,118 @@
|
||||
const _ = require('./underscore.js');
|
||||
const _ = require('./underscore.js')
|
||||
|
||||
function TokenizationError(message, token) {
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
this.name = this.constructor.name;
|
||||
function TokenizationError (message, token) {
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, this.constructor)
|
||||
}
|
||||
this.name = this.constructor.name
|
||||
|
||||
this.input = token.input;
|
||||
this.line = token.line;
|
||||
this.file = token.file;
|
||||
this.input = token.input
|
||||
this.line = token.line
|
||||
this.file = token.file
|
||||
|
||||
var context = mkContext(token.input, token.line);
|
||||
this.message = mkMessage(message, token);
|
||||
this.stack = context + '\n' + (this.stack || '');
|
||||
var context = mkContext(token.input, token.line)
|
||||
this.message = mkMessage(message, token)
|
||||
this.stack = context + '\n' + (this.stack || '')
|
||||
}
|
||||
TokenizationError.prototype = Object.create(Error.prototype);
|
||||
TokenizationError.prototype.constructor = TokenizationError;
|
||||
TokenizationError.prototype = Object.create(Error.prototype)
|
||||
TokenizationError.prototype.constructor = TokenizationError
|
||||
|
||||
function ParseError(e, token) {
|
||||
_.assign(this, e);
|
||||
this.originalError = e;
|
||||
this.name = this.constructor.name;
|
||||
function ParseError (e, token) {
|
||||
_.assign(this, e)
|
||||
this.originalError = e
|
||||
this.name = this.constructor.name
|
||||
|
||||
this.input = token.input;
|
||||
this.line = token.line;
|
||||
this.file = token.file;
|
||||
this.input = token.input
|
||||
this.line = token.line
|
||||
this.file = token.file
|
||||
|
||||
var context = mkContext(token.input, token.line);
|
||||
this.message = mkMessage(e.message || 'Unkown Error', token);
|
||||
this.stack = context + '\n' + (e.stack || '');
|
||||
var context = mkContext(token.input, token.line)
|
||||
this.message = mkMessage(e.message || 'Unkown Error', token)
|
||||
this.stack = context + '\n' + (e.stack || '')
|
||||
}
|
||||
ParseError.prototype = Object.create(Error.prototype);
|
||||
ParseError.prototype.constructor = ParseError;
|
||||
ParseError.prototype = Object.create(Error.prototype)
|
||||
ParseError.prototype.constructor = ParseError
|
||||
|
||||
function RenderError(e, tpl) {
|
||||
function RenderError (e, tpl) {
|
||||
// return the original render error
|
||||
if(e instanceof RenderError){
|
||||
return e;
|
||||
}
|
||||
_.assign(this, e);
|
||||
this.originalError = e;
|
||||
this.name = this.constructor.name;
|
||||
if (e instanceof RenderError) {
|
||||
return e
|
||||
}
|
||||
_.assign(this, e)
|
||||
this.originalError = e
|
||||
this.name = this.constructor.name
|
||||
|
||||
this.input = tpl.token.input;
|
||||
this.line = tpl.token.line;
|
||||
this.file = tpl.token.file;
|
||||
this.input = tpl.token.input
|
||||
this.line = tpl.token.line
|
||||
this.file = tpl.token.file
|
||||
|
||||
var context = mkContext(tpl.token.input, tpl.token.line);
|
||||
this.message = mkMessage(e.message || 'Unkown Error', tpl.token);
|
||||
this.stack = context + '\n' + (e.stack || '');
|
||||
var context = mkContext(tpl.token.input, tpl.token.line)
|
||||
this.message = mkMessage(e.message || 'Unkown Error', tpl.token)
|
||||
this.stack = context + '\n' + (e.stack || '')
|
||||
}
|
||||
RenderError.prototype = Object.create(Error.prototype);
|
||||
RenderError.prototype.constructor = RenderError;
|
||||
RenderError.prototype = Object.create(Error.prototype)
|
||||
RenderError.prototype.constructor = RenderError
|
||||
|
||||
function RenderBreakError(message) {
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
this.name = this.constructor.name;
|
||||
this.message = message || '';
|
||||
function RenderBreakError (message) {
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, this.constructor)
|
||||
}
|
||||
this.name = this.constructor.name
|
||||
this.message = message || ''
|
||||
}
|
||||
RenderBreakError.prototype = Object.create(Error.prototype);
|
||||
RenderBreakError.prototype.constructor = RenderBreakError;
|
||||
RenderBreakError.prototype = Object.create(Error.prototype)
|
||||
RenderBreakError.prototype.constructor = RenderBreakError
|
||||
|
||||
function AssertionError(message) {
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
this.name = this.constructor.name;
|
||||
this.message = message;
|
||||
function AssertionError (message) {
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, this.constructor)
|
||||
}
|
||||
this.name = this.constructor.name
|
||||
this.message = message
|
||||
}
|
||||
AssertionError.prototype = Object.create(Error.prototype);
|
||||
AssertionError.prototype.constructor = AssertionError;
|
||||
AssertionError.prototype = Object.create(Error.prototype)
|
||||
AssertionError.prototype.constructor = AssertionError
|
||||
|
||||
function mkContext(input, line) {
|
||||
var lines = input.split('\n');
|
||||
var begin = Math.max(line - 2, 1);
|
||||
var end = Math.min(line + 3, lines.length);
|
||||
function mkContext (input, line) {
|
||||
var lines = input.split('\n')
|
||||
var begin = Math.max(line - 2, 1)
|
||||
var end = Math.min(line + 3, lines.length)
|
||||
|
||||
var context = _
|
||||
var context = _
|
||||
.range(begin, end + 1)
|
||||
.map(l => [
|
||||
(l === line) ? '>> ' : ' ',
|
||||
align(l, end),
|
||||
'| ',
|
||||
lines[l - 1]
|
||||
(l === line) ? '>> ' : ' ',
|
||||
align(l, end),
|
||||
'| ',
|
||||
lines[l - 1]
|
||||
].join(''))
|
||||
.join('\n');
|
||||
.join('\n')
|
||||
|
||||
return context;
|
||||
return context
|
||||
}
|
||||
|
||||
function align(n, max) {
|
||||
var length = (max + '').length;
|
||||
var str = n + '';
|
||||
var blank = Array(length - str.length).join(' ');
|
||||
return blank + str;
|
||||
function align (n, max) {
|
||||
var length = (max + '').length
|
||||
var str = n + ''
|
||||
var blank = Array(length - str.length).join(' ')
|
||||
return blank + str
|
||||
}
|
||||
|
||||
function mkMessage(msg, token){
|
||||
msg = msg || '';
|
||||
if(token.file){
|
||||
msg += ', file:' + token.file;
|
||||
}
|
||||
if(token.line){
|
||||
msg += ', line:' + token.line;
|
||||
}
|
||||
return msg;
|
||||
function mkMessage (msg, token) {
|
||||
msg = msg || ''
|
||||
if (token.file) {
|
||||
msg += ', file:' + token.file
|
||||
}
|
||||
if (token.line) {
|
||||
msg += ', line:' + token.line
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
TokenizationError,
|
||||
ParseError,
|
||||
RenderBreakError,
|
||||
AssertionError,
|
||||
RenderError
|
||||
};
|
||||
TokenizationError,
|
||||
ParseError,
|
||||
RenderBreakError,
|
||||
AssertionError,
|
||||
RenderError
|
||||
}
|
||||
|
||||
+14
-14
@@ -1,20 +1,20 @@
|
||||
const fs = require('fs');
|
||||
const fs = require('fs')
|
||||
|
||||
function readFileAsync(filepath) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
fs.readFile(filepath, 'utf8', function(err, content) {
|
||||
err ? reject(err) : resolve(content);
|
||||
});
|
||||
});
|
||||
function readFileAsync (filepath) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.readFile(filepath, 'utf8', function (err, content) {
|
||||
err ? reject(err) : resolve(content)
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
function statFileAsync(path) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
fs.stat(path, (err, stat) => err ? reject(err) : resolve(stat))
|
||||
});
|
||||
function statFileAsync (path) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.stat(path, (err, stat) => err ? reject(err) : resolve(stat))
|
||||
})
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
readFileAsync,
|
||||
statFileAsync
|
||||
};
|
||||
readFileAsync,
|
||||
statFileAsync
|
||||
}
|
||||
|
||||
+19
-19
@@ -1,35 +1,35 @@
|
||||
const Promise = require('any-promise');
|
||||
const Promise = require('any-promise')
|
||||
|
||||
/*
|
||||
* Call functions in serial until someone resolved.
|
||||
* @param {Array} iterable the array to iterate with.
|
||||
* @param {Array} iteratee returns a new promise.
|
||||
* The iteratee is invoked with three arguments: (value, index, iterable).
|
||||
* The iteratee is invoked with three arguments: (value, index, iterable).
|
||||
*/
|
||||
function anySeries(iterable, iteratee) {
|
||||
var ret = Promise.reject(new Error('init'));
|
||||
iterable.forEach(function(item, idx) {
|
||||
ret = ret.catch(e => iteratee(item, idx, iterable));
|
||||
});
|
||||
return ret;
|
||||
function anySeries (iterable, iteratee) {
|
||||
var ret = Promise.reject(new Error('init'))
|
||||
iterable.forEach(function (item, idx) {
|
||||
ret = ret.catch(e => iteratee(item, idx, iterable))
|
||||
})
|
||||
return ret
|
||||
}
|
||||
|
||||
/*
|
||||
* Call functions in serial until someone rejected.
|
||||
* @param {Array} iterable the array to iterate with.
|
||||
* @param {Array} iteratee returns a new promise.
|
||||
* The iteratee is invoked with three arguments: (value, index, iterable).
|
||||
* The iteratee is invoked with three arguments: (value, index, iterable).
|
||||
*/
|
||||
function mapSeries(iterable, iteratee) {
|
||||
var ret = Promise.resolve('init');
|
||||
var result = [];
|
||||
iterable.forEach(function(item, idx) {
|
||||
ret = ret
|
||||
function mapSeries (iterable, iteratee) {
|
||||
var ret = Promise.resolve('init')
|
||||
var result = []
|
||||
iterable.forEach(function (item, idx) {
|
||||
ret = ret
|
||||
.then(() => iteratee(item, idx, iterable))
|
||||
.then(x => result.push(x));
|
||||
});
|
||||
return ret.then(() => result);
|
||||
.then(x => result.push(x))
|
||||
})
|
||||
return ret.then(() => result)
|
||||
}
|
||||
|
||||
exports.anySeries = anySeries;
|
||||
exports.mapSeries = mapSeries;
|
||||
exports.anySeries = anySeries
|
||||
exports.mapSeries = mapSeries
|
||||
|
||||
+180
-181
@@ -1,200 +1,199 @@
|
||||
var monthNames = [
|
||||
"January", "February", "March", "April", "May", "June", "July", "August",
|
||||
"September", "October", "November", "December"
|
||||
];
|
||||
'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
|
||||
'September', 'October', 'November', 'December'
|
||||
]
|
||||
var monthNamesShort = [
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
|
||||
"Nov", "Dec"
|
||||
];
|
||||
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct',
|
||||
'Nov', 'Dec'
|
||||
]
|
||||
var dayNames = [
|
||||
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
|
||||
];
|
||||
var dayNamesShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||
'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
|
||||
]
|
||||
var dayNamesShort = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
|
||||
var suffixes = {
|
||||
1: 'st',
|
||||
2: 'nd',
|
||||
3: 'rd',
|
||||
'default': 'th'
|
||||
};
|
||||
1: 'st',
|
||||
2: 'nd',
|
||||
3: 'rd',
|
||||
'default': 'th'
|
||||
}
|
||||
|
||||
// prototype extensions
|
||||
var _date = {
|
||||
daysInMonth: function(d) {
|
||||
var feb = _date.isLeapYear(d) ? 29 : 28;
|
||||
return [31, feb, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||
},
|
||||
daysInMonth: function (d) {
|
||||
var feb = _date.isLeapYear(d) ? 29 : 28
|
||||
return [31, feb, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||
},
|
||||
|
||||
getDayOfYear: function(d) {
|
||||
var num = 0;
|
||||
for (var i = 0; i < d.getMonth(); ++i) {
|
||||
num += _date.daysInMonth(d)[i];
|
||||
}
|
||||
return num + d.getDate();
|
||||
},
|
||||
|
||||
// Startday is an integer of which day to start the week measuring from
|
||||
// TODO: that comment was retarted. fix it.
|
||||
getWeekOfYear: function(d, startDay) {
|
||||
// Skip to startDay of this week
|
||||
var now = this.getDayOfYear(d) + (startDay - d.getDay());
|
||||
// Find the first startDay of the year
|
||||
var jan1 = new Date(d.getFullYear(), 0, 1);
|
||||
var then = (7 - jan1.getDay() + startDay);
|
||||
return _number.pad(Math.floor((now - then) / 7) + 1, 2);
|
||||
},
|
||||
|
||||
isLeapYear: function(d) {
|
||||
var year = d.getFullYear();
|
||||
return !!((year & 3) === 0 && (year % 100 || (year % 400 === 0 && year)));
|
||||
},
|
||||
|
||||
getSuffix: function(d) {
|
||||
var str = d.getDate().toString();
|
||||
var index = parseInt(str.slice(-1));
|
||||
return suffixes[index] || suffixes['default'];
|
||||
},
|
||||
|
||||
century: function(d) {
|
||||
return parseInt(d.getFullYear().toString().substring(0, 2), 10);
|
||||
getDayOfYear: function (d) {
|
||||
var num = 0
|
||||
for (var i = 0; i < d.getMonth(); ++i) {
|
||||
num += _date.daysInMonth(d)[i]
|
||||
}
|
||||
};
|
||||
return num + d.getDate()
|
||||
},
|
||||
|
||||
// Startday is an integer of which day to start the week measuring from
|
||||
// TODO: that comment was retarted. fix it.
|
||||
getWeekOfYear: function (d, startDay) {
|
||||
// Skip to startDay of this week
|
||||
var now = this.getDayOfYear(d) + (startDay - d.getDay())
|
||||
// Find the first startDay of the year
|
||||
var jan1 = new Date(d.getFullYear(), 0, 1)
|
||||
var then = (7 - jan1.getDay() + startDay)
|
||||
return _number.pad(Math.floor((now - then) / 7) + 1, 2)
|
||||
},
|
||||
|
||||
isLeapYear: function (d) {
|
||||
var year = d.getFullYear()
|
||||
return !!((year & 3) === 0 && (year % 100 || (year % 400 === 0 && year)))
|
||||
},
|
||||
|
||||
getSuffix: function (d) {
|
||||
var str = d.getDate().toString()
|
||||
var index = parseInt(str.slice(-1))
|
||||
return suffixes[index] || suffixes['default']
|
||||
},
|
||||
|
||||
century: function (d) {
|
||||
return parseInt(d.getFullYear().toString().substring(0, 2), 10)
|
||||
}
|
||||
}
|
||||
|
||||
var _number = {
|
||||
pad: function(value, size, ch) {
|
||||
if (!ch) ch = '0';
|
||||
var result = value.toString();
|
||||
var pad = size - result.length;
|
||||
pad: function (value, size, ch) {
|
||||
if (!ch) ch = '0'
|
||||
var result = value.toString()
|
||||
var pad = size - result.length
|
||||
|
||||
while (pad-- > 0) {
|
||||
result = ch + result;
|
||||
}
|
||||
|
||||
return result;
|
||||
while (pad-- > 0) {
|
||||
result = ch + result
|
||||
}
|
||||
};
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
var format_codes = {
|
||||
a: function(d) {
|
||||
return dayNamesShort[d.getDay()];
|
||||
},
|
||||
A: function(d) {
|
||||
return dayNames[d.getDay()];
|
||||
},
|
||||
b: function(d) {
|
||||
return monthNamesShort[d.getMonth()];
|
||||
},
|
||||
B: function(d) {
|
||||
return monthNames[d.getMonth()];
|
||||
},
|
||||
c: function(d) {
|
||||
return d.toLocaleString();
|
||||
},
|
||||
C: function(d) {
|
||||
return _date.century(d);
|
||||
},
|
||||
d: function(d) {
|
||||
return _number.pad(d.getDate(), 2);
|
||||
},
|
||||
e: function(d) {
|
||||
return _number.pad(d.getDate(), 2, ' ');
|
||||
},
|
||||
H: function(d) {
|
||||
return _number.pad(d.getHours(), 2);
|
||||
},
|
||||
I: function(d) {
|
||||
return _number.pad(d.getHours() % 12 || 12, 2);
|
||||
},
|
||||
j: function(d) {
|
||||
return _number.pad(_date.getDayOfYear(d), 3);
|
||||
},
|
||||
k: function(d) {
|
||||
return _number.pad(d.getHours(), 2, ' ');
|
||||
},
|
||||
l: function(d) {
|
||||
return _number.pad(d.getHours() % 12 || 12, 2, ' ');
|
||||
},
|
||||
L: function(d) {
|
||||
return _number.pad(d.getMilliseconds(), 3);
|
||||
},
|
||||
m: function(d) {
|
||||
return _number.pad(d.getMonth() + 1, 2);
|
||||
},
|
||||
M: function(d) {
|
||||
return _number.pad(d.getMinutes(), 2);
|
||||
},
|
||||
p: function(d) {
|
||||
return (d.getHours() < 12 ? 'AM' : 'PM');
|
||||
},
|
||||
P: function(d) {
|
||||
return (d.getHours() < 12 ? 'am' : 'pm');
|
||||
},
|
||||
q: function(d) {
|
||||
return _date.getSuffix(d);
|
||||
},
|
||||
s: function(d) {
|
||||
return Math.round(d.valueOf() / 1000);
|
||||
},
|
||||
S: function(d) {
|
||||
return _number.pad(d.getSeconds(), 2);
|
||||
},
|
||||
u: function(d) {
|
||||
return d.getDay() || 7;
|
||||
},
|
||||
U: function(d) {
|
||||
return _date.getWeekOfYear(d, 0);
|
||||
},
|
||||
w: function(d) {
|
||||
return d.getDay();
|
||||
},
|
||||
W: function(d) {
|
||||
return _date.getWeekOfYear(d, 1);
|
||||
},
|
||||
x: function(d) {
|
||||
return d.toLocaleDateString();
|
||||
},
|
||||
X: function(d) {
|
||||
return d.toLocaleTimeString();
|
||||
},
|
||||
y: function(d) {
|
||||
return d.getFullYear().toString().substring(2, 4);
|
||||
},
|
||||
Y: function(d) {
|
||||
return d.getFullYear();
|
||||
},
|
||||
z: function(d) {
|
||||
var tz = d.getTimezoneOffset() / 60 * 100;
|
||||
return (tz > 0 ? '-' : '+') + _number.pad(Math.abs(tz), 4);
|
||||
},
|
||||
"%": function() {
|
||||
return '%';
|
||||
var formatCodes = {
|
||||
a: function (d) {
|
||||
return dayNamesShort[d.getDay()]
|
||||
},
|
||||
A: function (d) {
|
||||
return dayNames[d.getDay()]
|
||||
},
|
||||
b: function (d) {
|
||||
return monthNamesShort[d.getMonth()]
|
||||
},
|
||||
B: function (d) {
|
||||
return monthNames[d.getMonth()]
|
||||
},
|
||||
c: function (d) {
|
||||
return d.toLocaleString()
|
||||
},
|
||||
C: function (d) {
|
||||
return _date.century(d)
|
||||
},
|
||||
d: function (d) {
|
||||
return _number.pad(d.getDate(), 2)
|
||||
},
|
||||
e: function (d) {
|
||||
return _number.pad(d.getDate(), 2, ' ')
|
||||
},
|
||||
H: function (d) {
|
||||
return _number.pad(d.getHours(), 2)
|
||||
},
|
||||
I: function (d) {
|
||||
return _number.pad(d.getHours() % 12 || 12, 2)
|
||||
},
|
||||
j: function (d) {
|
||||
return _number.pad(_date.getDayOfYear(d), 3)
|
||||
},
|
||||
k: function (d) {
|
||||
return _number.pad(d.getHours(), 2, ' ')
|
||||
},
|
||||
l: function (d) {
|
||||
return _number.pad(d.getHours() % 12 || 12, 2, ' ')
|
||||
},
|
||||
L: function (d) {
|
||||
return _number.pad(d.getMilliseconds(), 3)
|
||||
},
|
||||
m: function (d) {
|
||||
return _number.pad(d.getMonth() + 1, 2)
|
||||
},
|
||||
M: function (d) {
|
||||
return _number.pad(d.getMinutes(), 2)
|
||||
},
|
||||
p: function (d) {
|
||||
return (d.getHours() < 12 ? 'AM' : 'PM')
|
||||
},
|
||||
P: function (d) {
|
||||
return (d.getHours() < 12 ? 'am' : 'pm')
|
||||
},
|
||||
q: function (d) {
|
||||
return _date.getSuffix(d)
|
||||
},
|
||||
s: function (d) {
|
||||
return Math.round(d.valueOf() / 1000)
|
||||
},
|
||||
S: function (d) {
|
||||
return _number.pad(d.getSeconds(), 2)
|
||||
},
|
||||
u: function (d) {
|
||||
return d.getDay() || 7
|
||||
},
|
||||
U: function (d) {
|
||||
return _date.getWeekOfYear(d, 0)
|
||||
},
|
||||
w: function (d) {
|
||||
return d.getDay()
|
||||
},
|
||||
W: function (d) {
|
||||
return _date.getWeekOfYear(d, 1)
|
||||
},
|
||||
x: function (d) {
|
||||
return d.toLocaleDateString()
|
||||
},
|
||||
X: function (d) {
|
||||
return d.toLocaleTimeString()
|
||||
},
|
||||
y: function (d) {
|
||||
return d.getFullYear().toString().substring(2, 4)
|
||||
},
|
||||
Y: function (d) {
|
||||
return d.getFullYear()
|
||||
},
|
||||
z: function (d) {
|
||||
var tz = d.getTimezoneOffset() / 60 * 100
|
||||
return (tz > 0 ? '-' : '+') + _number.pad(Math.abs(tz), 4)
|
||||
},
|
||||
'%': function () {
|
||||
return '%'
|
||||
}
|
||||
}
|
||||
formatCodes.h = formatCodes.b
|
||||
formatCodes.N = formatCodes.L
|
||||
|
||||
var strftime = function (d, format) {
|
||||
var output = ''
|
||||
var remaining = format
|
||||
|
||||
while (true) {
|
||||
var r = /%./g
|
||||
var results = r.exec(remaining)
|
||||
|
||||
// No more format codes. Add the remaining text and return
|
||||
if (!results) {
|
||||
return output + remaining
|
||||
}
|
||||
};
|
||||
format_codes.h = format_codes.b;
|
||||
format_codes.N = format_codes.L;
|
||||
|
||||
var strftime = function(d, format) {
|
||||
var output = '';
|
||||
var remaining = format;
|
||||
// Add the preceding text
|
||||
output += remaining.slice(0, r.lastIndex - 2)
|
||||
remaining = remaining.slice(r.lastIndex)
|
||||
|
||||
while (true) {
|
||||
var r = /%./g;
|
||||
var results = r.exec(remaining);
|
||||
// Add the format code
|
||||
var ch = results[0].charAt(1)
|
||||
var func = formatCodes[ch]
|
||||
output += func ? func.call(this, d) : '%' + ch
|
||||
}
|
||||
}
|
||||
|
||||
// No more format codes. Add the remaining text and return
|
||||
if (!results) {
|
||||
return output + remaining;
|
||||
}
|
||||
|
||||
// Add the preceding text
|
||||
output += remaining.slice(0, r.lastIndex - 2);
|
||||
remaining = remaining.slice(r.lastIndex);
|
||||
|
||||
// Add the format code
|
||||
var ch = results[0].charAt(1);
|
||||
var func = format_codes[ch];
|
||||
output += func ? func.call(this, d) : '%' + ch;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = strftime;
|
||||
module.exports = strftime
|
||||
|
||||
+76
-77
@@ -3,39 +3,39 @@
|
||||
* @param {any} value The value to check.
|
||||
* @return {Boolean} Returns true if value is a string, else false.
|
||||
*/
|
||||
function isString(value) {
|
||||
return value instanceof String || typeof value === 'string';
|
||||
function isString (value) {
|
||||
return value instanceof String || typeof value === 'string'
|
||||
}
|
||||
|
||||
function isError(value) {
|
||||
var signature = Object.prototype.toString.call(value);
|
||||
function isError (value) {
|
||||
var signature = Object.prototype.toString.call(value)
|
||||
// [object XXXError]
|
||||
return signature.substr(-6, 5) === 'Error' ||
|
||||
(typeof value.message == 'string' && typeof value.name == 'string');
|
||||
return signature.substr(-6, 5) === 'Error' ||
|
||||
(typeof value.message === 'string' && typeof value.name === 'string')
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterates over own enumerable string keyed properties of an object and invokes iteratee for each property.
|
||||
* The iteratee is invoked with three arguments: (value, key, object).
|
||||
* Iterates over own enumerable string keyed properties of an object and invokes iteratee for each property.
|
||||
* The iteratee is invoked with three arguments: (value, key, object).
|
||||
* Iteratee functions may exit iteration early by explicitly returning false.
|
||||
* @param {Object} object The object to iterate over.
|
||||
* @param {Function} iteratee The function invoked per iteration.
|
||||
* @return {Object} Returns object.
|
||||
*/
|
||||
function forOwn(object, iteratee) {
|
||||
object = object || {};
|
||||
for (var k in object) {
|
||||
if (object.hasOwnProperty(k)) {
|
||||
if (iteratee(object[k], k, object) === false) break;
|
||||
}
|
||||
function forOwn (object, iteratee) {
|
||||
object = object || {}
|
||||
for (var k in object) {
|
||||
if (object.hasOwnProperty(k)) {
|
||||
if (iteratee(object[k], k, object) === false) break
|
||||
}
|
||||
return object;
|
||||
}
|
||||
return object
|
||||
}
|
||||
|
||||
/*
|
||||
* Assigns own enumerable string keyed properties of source objects to the destination object.
|
||||
* Source objects are applied from left to right.
|
||||
* Subsequent sources overwrite property assignments of previous sources.
|
||||
* Assigns own enumerable string keyed properties of source objects to the destination object.
|
||||
* Source objects are applied from left to right.
|
||||
* Subsequent sources overwrite property assignments of previous sources.
|
||||
*
|
||||
* Note: This method mutates object and is loosely based on Object.assign.
|
||||
*
|
||||
@@ -43,89 +43,88 @@ function forOwn(object, iteratee) {
|
||||
* @param {...Object} sources The source objects.
|
||||
* @return {Object} Returns object.
|
||||
*/
|
||||
function assign(object) {
|
||||
object = isObject(object) ? object : {};
|
||||
var srcs = Array.prototype.slice.call(arguments, 1);
|
||||
srcs.forEach(function(src) {
|
||||
_assignBinary(object, src);
|
||||
});
|
||||
return object;
|
||||
function assign (object) {
|
||||
object = isObject(object) ? object : {}
|
||||
var srcs = Array.prototype.slice.call(arguments, 1)
|
||||
srcs.forEach(function (src) {
|
||||
_assignBinary(object, src)
|
||||
})
|
||||
return object
|
||||
}
|
||||
|
||||
function _assignBinary(dst, src) {
|
||||
if (!dst) return dst;
|
||||
forOwn(src, function(v, k) {
|
||||
dst[k] = v;
|
||||
});
|
||||
return dst;
|
||||
function _assignBinary (dst, src) {
|
||||
if (!dst) return dst
|
||||
forOwn(src, function (v, k) {
|
||||
dst[k] = v
|
||||
})
|
||||
return dst
|
||||
}
|
||||
|
||||
|
||||
function isArray(value) {
|
||||
return value instanceof Array;
|
||||
function isArray (value) {
|
||||
return value instanceof Array
|
||||
}
|
||||
|
||||
function echo(prefix) {
|
||||
return v => {
|
||||
console.log('[' + prefix + ']', v);
|
||||
return v;
|
||||
};
|
||||
function echo (prefix) {
|
||||
return v => {
|
||||
console.log('[' + prefix + ']', v)
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
function uniq(arr) {
|
||||
var u = {},
|
||||
a = [];
|
||||
for (var i = 0, l = arr.length; i < l; ++i) {
|
||||
if (u.hasOwnProperty(arr[i])) {
|
||||
continue;
|
||||
}
|
||||
a.push(arr[i]);
|
||||
u[arr[i]] = 1;
|
||||
function uniq (arr) {
|
||||
var u = {}
|
||||
var a = []
|
||||
for (var i = 0, l = arr.length; i < l; ++i) {
|
||||
if (u.hasOwnProperty(arr[i])) {
|
||||
continue
|
||||
}
|
||||
return a;
|
||||
a.push(arr[i])
|
||||
u[arr[i]] = 1
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if value is the language type of Object.
|
||||
* Checks if value is the language type of Object.
|
||||
* (e.g. arrays, functions, objects, regexes, new Number(0), and new String(''))
|
||||
* @param {any} value The value to check.
|
||||
* @return {Boolean} Returns true if value is an object, else false.
|
||||
*/
|
||||
function isObject(value) {
|
||||
return value !== null && typeof value === 'object';
|
||||
function isObject (value) {
|
||||
return value !== null && typeof value === 'object'
|
||||
}
|
||||
|
||||
/*
|
||||
* A function to create flexibly-numbered lists of integers,
|
||||
* handy for each and map loops. start, if omitted, defaults to 0; step defaults to 1.
|
||||
* Returns a list of integers from start (inclusive) to stop (exclusive),
|
||||
* incremented (or decremented) by step, exclusive.
|
||||
* Note that ranges that stop before they start are considered to be zero-length instead of
|
||||
* A function to create flexibly-numbered lists of integers,
|
||||
* handy for each and map loops. start, if omitted, defaults to 0; step defaults to 1.
|
||||
* Returns a list of integers from start (inclusive) to stop (exclusive),
|
||||
* incremented (or decremented) by step, exclusive.
|
||||
* Note that ranges that stop before they start are considered to be zero-length instead of
|
||||
* negative — if you'd like a negative range, use a negative step.
|
||||
*/
|
||||
function range(start, stop, step) {
|
||||
if (arguments.length === 1) {
|
||||
stop = start;
|
||||
start = 0;
|
||||
}
|
||||
step = step || 1;
|
||||
function range (start, stop, step) {
|
||||
if (arguments.length === 1) {
|
||||
stop = start
|
||||
start = 0
|
||||
}
|
||||
step = step || 1
|
||||
|
||||
var arr = [];
|
||||
for (var i = start; i < stop; i += step) {
|
||||
arr.push(i);
|
||||
}
|
||||
return arr;
|
||||
var arr = []
|
||||
for (var i = start; i < stop; i += step) {
|
||||
arr.push(i)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
exports.isString = isString;
|
||||
exports.isArray = isArray;
|
||||
exports.isObject = isObject;
|
||||
exports.isError = isError;
|
||||
exports.isString = isString
|
||||
exports.isArray = isArray
|
||||
exports.isObject = isObject
|
||||
exports.isError = isError
|
||||
|
||||
exports.range = range;
|
||||
exports.range = range
|
||||
|
||||
exports.forOwn = forOwn;
|
||||
exports.assign = assign;
|
||||
exports.uniq = uniq;
|
||||
exports.forOwn = forOwn
|
||||
exports.assign = assign
|
||||
exports.uniq = uniq
|
||||
|
||||
exports.echo = echo;
|
||||
exports.echo = echo
|
||||
|
||||
Reference in New Issue
Block a user