enhancement: decrease dist size

This commit is contained in:
harttle
2016-10-04 22:31:28 +08:00
parent 1e1b6e8cc3
commit 77930e2d20
30 changed files with 2724 additions and 3934 deletions
+1 -1
View File
@@ -101,7 +101,7 @@ And `window.Liquid` is what you want.
```html
<html lang="en">
<head>
<script src="shopify-liquid.min.js"></script>
<script src="dist/liquid.min.js"></script>
</head>
<body>
<script>
+5 -3
View File
@@ -4,7 +4,7 @@
<head>
<meta charset="UTF-8">
<title></title>
<script src="../../dist/shopify-liquid.min.js"></script>
<script src="../../dist/liquid.js"></script>
</head>
<body>
@@ -12,9 +12,11 @@
<script>
var engine = window.Liquid();
var src = '{{ name | capitalize}}';
var src = 'Welcome to {{ name | capitalize}}, ' +
'access time: {{date|date: "%Y-%m-%d %H:%M:%S"}}';
var ctx = {
name: 'welcome to Shopify Liquid'
name: 'Liquid',
date: new Date()
};
engine.parseAndRender(src, ctx)
.then(function(html) {
+2251
View File
File diff suppressed because it is too large Load Diff
+2
View File
File diff suppressed because one or more lines are too long
-3858
View File
File diff suppressed because it is too large Load Diff
-4
View File
File diff suppressed because one or more lines are too long
+4 -2
View File
@@ -1,4 +1,5 @@
const strftime = require('strftime').timezone(-(new Date()).getTimezoneOffset());
//const strftime = require('strftime').timezone(-(new Date()).getTimezoneOffset());
const strftime = require('./src/strftime.js');
module.exports = function(liquid) {
liquid.registerFilter('abs', v => Math.abs(v));
@@ -7,7 +8,8 @@ module.exports = function(liquid) {
(str || '').charAt(0).toUpperCase() + str.slice(1));
liquid.registerFilter('ceil', v => Math.ceil(v));
liquid.registerFilter('date', (v, arg) => strftime(arg, v));
//liquid.registerFilter('date', (v, arg) => strftime(arg, v));
liquid.registerFilter('date', (v, arg) => strftime(v, arg));
liquid.registerFilter('default', (v, arg) => arg || v);
liquid.registerFilter('divided_by', (v, arg) => Math.floor(v / arg));
+19 -6
View File
@@ -1,10 +1,8 @@
const Scope = require('./src/scope');
const assert = require('assert');
const tokenizer = require('./src/tokenizer.js');
const fs = require('fs');
const Render = require('./src/render.js');
const lexical = require('./src/lexical.js');
const path = require("path");
const fs = require('fs');
const Tag = require('./src/tag.js');
const Filter = require('./src/filter.js');
const Template = require('./src/parser');
@@ -75,9 +73,11 @@ var _engine = {
return this.tag.register(name, tag);
},
handleCache: function(filepath) {
assert(filepath, 'filepath cannot be null');
filepath = path.resolve(this.options.root, filepath);
if (path.extname(filepath) === '') {
if (!filepath) throw new Error('filepath cannot be null');
filepath = resolvePath(this.options.root, filepath);
if (!filepath.match(/\.\w+$/)) {
filepath += this.options.extname;
}
@@ -114,6 +114,19 @@ function factory(options) {
return engine;
}
function resolvePath(root, path) {
if (path[0] == '/') return path;
var arr = root.split('/').concat(path.split('/'));
var result = [];
arr.forEach(function(slug) {
if (slug == '..') result.pop();
else if (!slug || slug == '.');
else result.push(slug);
});
return '/' + result.join('/');
}
factory.lexical = lexical;
factory.isTruthy = Expression.isTruthy;
factory.isFalsy = Expression.isFalsy;
+2 -2
View File
@@ -9,8 +9,8 @@ dist:
[ -d dist/ ] || mkdir dist/
$(BROWSERIFY) index.js -s Liquid \
-t [ babelify --global true --presets [ es2015 ] ] \
> dist/shopify-liquid.js
$(MINIFY) dist/shopify-liquid.js --output dist/shopify-liquid.min.js
> dist/liquid.js
$(MINIFY) dist/liquid.js --compress warnings=false --mangle --output dist/liquid.min.js
ls -lh dist/
clean:
+2 -3
View File
@@ -1,6 +1,6 @@
{
"name": "shopify-liquid",
"version": "1.2.1",
"version": "1.2.2",
"description": "Liquid template engine in Node.js (Shopify compliant)",
"main": "index.js",
"scripts": {
@@ -25,8 +25,7 @@
},
"homepage": "https://github.com/harttle/shopify-liquid#readme",
"dependencies": {
"any-promise": "^1.3.0",
"strftime": "^0.9.2"
"any-promise": "^1.3.0"
},
"devDependencies": {
"babel-preset-es2015": "^6.14.0",
+6 -5
View File
@@ -1,5 +1,3 @@
const util = require('util');
function TokenizationError(message, input, line) {
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
@@ -8,17 +6,20 @@ function TokenizationError(message, input, line) {
this.input = input;
this.line = line;
}
util.inherits(TokenizationError, Error);
TokenizationError.prototype = Object.create(Error.prototype);
TokenizationError.prototype.constructor = TokenizationError;
function ParseError(message, input, line) {
function ParseError(message, input, line, e) {
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.originalError = e;
this.message = message || "";
this.input = input;
this.line = line;
}
util.inherits(ParseError, Error);
ParseError.prototype = Object.create(Error.prototype);
ParseError.prototype.constructor = ParseError;
module.exports = {
TokenizationError, ParseError
+4 -4
View File
@@ -1,11 +1,11 @@
const Liquid = require('..');
module.exports = function() {
var engine = Liquid({
root: '/root/',
extname: '.html'
});
var engine = Liquid({
root: '/root/',
extname: '.html'
});
function express(filePath, options, callback) {
fs.readFile(filePath, function(err, content) {
if (err) return callback(new Error(err));
-2
View File
@@ -1,5 +1,4 @@
const syntax = require('./syntax.js');
const Exp = require('./expression.js');
const lexical = require('./lexical.js');
function evalExp(exp, scope) {
@@ -35,7 +34,6 @@ function evalValue(str, scope) {
if (!str) return undefined;
if (lexical.isLiteral(str)) {
var a = lexical.parseLiteral(str);
return lexical.parseLiteral(str);
}
if (lexical.isVariable(str)) {
+2 -1
View File
@@ -22,6 +22,7 @@ module.exports = function(Tag, Filter) {
},
start: function() {
this.trigger('start');
var token;
while (!this.stopRequested && (token = this.tokens.shift())) {
if (this.trigger('token', token)) continue;
if (token.type == 'tag' &&
@@ -59,7 +60,7 @@ module.exports = function(Tag, Filter) {
return token;
}
} catch (e) {
throw new ParseError(e.message, token.input, token.line);
throw new ParseError(e.message, token.input, token.line, e);
}
}
+2 -4
View File
@@ -1,12 +1,10 @@
const error = require('./error.js');
const Exp = require('./expression.js');
const assert = require('assert');
const Promise = require('any-promise');
var render = {
renderTemplates: function(templates, scope, opts) {
assert(scope, 'unable to evalTemplates: scope undefined');
if(!scope) throw new Error('unable to evalTemplates: scope undefined');
opts = opts || {};
opts.strict_filters = opts.strict_filters || false;
@@ -90,7 +88,7 @@ var render = {
},
evalOutput: function(template, scope, opts) {
assert(scope, 'unable to evalOutput: scope undefined');
if(!scope) throw new Error('unable to evalOutput: scope undefined');
var val = Exp.evalExp(template.initial, scope);
template.filters.some(filter => {
if (filter.error) {
-2
View File
@@ -1,5 +1,3 @@
const lexical = require('./lexical.js');
var Scope = {
safeGet: function(str) {
var i;
+404
View File
@@ -0,0 +1,404 @@
var monthNames = [
"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"
];
var dayNames = [
"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'
};
// 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];
},
getTimezone: function(d) {
return d.toString().replace(
/^.*? ([A-Z]{3}) [0-9]{4}.*$/, "$1"
).replace(
/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, "$1$2$3"
);
},
getGMTOffset: function(d) {
return (d.getTimezoneOffset() > 0 ? "-" : "+") +
_number.pad(Math.floor(d.getTimezoneOffset() / 60), 2) +
_number.pad(d.getTimezoneOffset() % 60, 2);
},
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)));
},
getFirstDayOfMonth: function(d) {
var day = (d.getDay() - (d.getDate() - 1)) % 7;
return (day < 0) ? (day + 7) : day;
},
getLastDayOfMonth: function(d) {
var day = (d.getDay() + (_date.daysInMonth(d)[d.getMonth()] - d.getDate())) % 7;
return (day < 0) ? (day + 7) : day;
},
getSuffix: function(d) {
var str = d.getDate().toString();
var index = parseInt(str.slice(-1));
return suffixes[index] || suffixes['default'];
},
applyOffset: function(date, offset_seconds) {
date.setTime(date.valueOf() - offset_seconds * 1000);
return date;
},
century: function(d) {
return parseInt(d.getFullYear().toString().substring(0, 2), 10);
}
};
var _obj = {
values_of: function(obj) {
var values = [];
for(var k in obj){
if(obj.hasOwnProperty(k)){
values.push(obj[k]);
}
}
return values;
}
};
var _number = {
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;
}
};
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();
},
// TODO: guessing the pad function won't work with negative numbers?
// TODO: getTimezoneOffset returns a positive number for GMT-7. Verify my
// assumption that it will return negative for GMT+x
z: function(d) {
var tz = d.getTimezoneOffset() / 60 * 100;
return (tz > 0 ? '-' : '+') + _number.pad(tz, 4);
},
"%": function() {
return '%';
}
};
format_codes.h = format_codes.b;
format_codes.N = format_codes.L;
// * r stands for regex, p stands for parser
// * all parseInt calls have to have the base supplied as the second
// parameter, otherwise they will default to octal when parsing numbers
// with leading zeros. This is most evident when parsing a date with 08 as
// the minutes / year as 08 is an invalid octal number, and so returns 0
var parse_codes = {
a: {
r: "(?:" + dayNamesShort.join("|") + ")"
},
A: {
r: "(?:" + dayNames.join("|") + ")"
},
b: {
r: "(" + monthNamesShort.join("|") + ")",
p: function(data) {
this.month = $.inArray(data, monthNamesShort);
}
},
B: {
r: "(" + monthNames.join("|") + ")",
p: function(data) {
this.month = $.inArray(data, monthNames);
}
},
C: {
r: "(\\d{1,2})",
p: function(d) {
this.century = parseInt(d, 10);
}
},
d: {
r: "(\\d{1,2})",
p: function(d) {
this.day = parseInt(d, 10);
}
},
H: {
r: "(\\d{1,2})",
p: function(d) {
this.hour = parseInt(d, 10);
}
},
// This gives only the day. Parsing of the month happens at the end because
// we also need the year
j: {
r: "(\\d{1,3})",
p: function(d) {
this.day = parseInt(d, 10);
}
},
L: {
r: "(\\d{3})",
p: function(d) {
this.milliseconds = parseInt(d, 10);
}
},
m: {
r: "(\\d{1,2})",
p: function(d) {
this.month = parseInt(d, 10) - 1;
}
},
M: {
r: "(\\d{2})",
p: function(d) {
this.minute = parseInt(d, 10);
}
},
p: {
r: "(AM|PM)",
p: function(d) {
if (d == 'AM') {
if (this.hour == 12) {
this.hour = 0;
}
} else {
if (this.hour < 12) {
this.hour += 12;
}
}
}
},
P: {
r: "(am|pm)",
p: function(d) {
if (d == 'am') {
if (this.hour == 12) {
this.hour = 0;
}
} else {
if (this.hour < 12) {
this.hour += 12;
}
}
}
},
q: {
r: "(?:" + _obj.values_of(suffixes).join('|') + ")"
},
S: {
r: "(\\d{2})",
p: function(d) {
this.second = parseInt(d, 10);
}
},
y: {
r: "(\\d{1,2})",
p: function(d) {
this.year = parseInt(d, 10);
}
},
Y: {
r: "(\\d{4})",
p: function(d) {
this.century = Math.floor(parseInt(d, 10) / 100);
this.year = parseInt(d, 10) % 100;
}
},
z: { // "Z", "+05:00", "+0500" all acceptable.
r: "(Z|[+-]\\d{2}:?\\d{2})",
p: function(d) {
// UTC, no offset.
if (d == "Z") {
this.zone = 0;
return;
}
var seconds = parseInt(d[0] + d[1] + d[2], 10) * 3600; // e.g., "+05" or "-08"
if (d[3] == ":") {
// "+HH:MM" is preferred iso8601 format
seconds += parseInt(d[4] + d[5], 10) * 60;
} else {
// "+HHMM" is frequently used, though.
seconds += parseInt(d[3] + d[4], 10) * 60;
}
this.zone = seconds;
}
}
};
parse_codes.e = parse_codes.d;
parse_codes.h = parse_codes.b;
parse_codes.I = parse_codes.H;
parse_codes.k = parse_codes.H;
parse_codes.l = parse_codes.H;
var strftime = function(d, format) {
// I used to use string split with a regex and a capturing block here,
// which I thought was really clever, but apparently this exact feature is
// fucked in IE. In every other browser (and languages), the captured
// blocks are present in the output. E.g.
// var pairs = "hello%athere".split(/(%.)/);
// => ['hello', '%a', 'there']
// IE however, just treats it the same as if no capturing block is present
// => ['hello', 'there']
// An alternate implementation of split is available here
// http://blog.stevenlevithan.com/archives/cross-browser-split
// Because that's a large amount of code for this one specific use case,
// I've just decided to loop through a regex instead.
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;
}
// 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;
+1 -2
View File
@@ -1,10 +1,9 @@
const lexical = require('./lexical.js');
const Promise = require('any-promise');
const Exp = require('./expression.js');
const TokenizationError = require('./error.js').TokenizationError;
function hash(markup, scope) {
var obj = {};
var obj = {}, match;
lexical.hashCapture.lastIndex = 0;
while (match = lexical.hashCapture.exec(markup)) {
var k = match[1],
+1 -1
View File
@@ -1,6 +1,6 @@
var Liquid = require('..');
var Promise = require('any-promise');
var lexical = Liquid.lexical;
var Promise = require('any-promise');
var re = new RegExp(`(${lexical.identifier.source})\\s*=(.*)`);
module.exports = function(liquid) {
-1
View File
@@ -1,5 +1,4 @@
var Liquid = require('..');
var lexical = Liquid.lexical;
module.exports = function(liquid) {
liquid.registerTag('case', {
-4
View File
@@ -1,7 +1,3 @@
var Liquid = require('..');
var lexical = Liquid.lexical;
var re = new RegExp(`(${lexical.identifier.source})`);
module.exports = function(liquid) {
liquid.registerTag('comment', {
-1
View File
@@ -1,6 +1,5 @@
const Liquid = require('..');
const lexical = Liquid.lexical;
const error = Liquid.error;
module.exports = function(liquid) {
-1
View File
@@ -1,5 +1,4 @@
var Liquid = require('..');
var lexical = Liquid.lexical;
module.exports = function(liquid) {
liquid.registerTag('if', {
-1
View File
@@ -1,5 +1,4 @@
var Liquid = require('..');
var Promise = require('any-promise');
var lexical = Liquid.lexical;
var withRE = new RegExp(`with\\s+(${lexical.value.source})`);
-15
View File
@@ -1,7 +1,6 @@
var Liquid = require('..');
var Promise = require('any-promise');
var lexical = Liquid.lexical;
var withRE = new RegExp(`with\\s+(${lexical.value.source})`);
module.exports = function(liquid) {
@@ -35,14 +34,6 @@ module.exports = function(liquid) {
e.file = layout;
throw e;
});
// var tpl = liquid.handleCache(layout);
//
// scope.push({});
// liquid.renderer.renderTemplates(this.tpls, scope); // what's the point of this line?
// var html = liquid.renderer.renderTemplates(tpl, scope);
// scope.pop();
// return html;
}
});
@@ -75,12 +66,6 @@ module.exports = function(liquid) {
promise = Promise.resolve(html);
}
return promise;
// if(html === undefined){
// html = liquid.renderer.renderTemplates(this.tpls, scope);
// }
// scope.set(`_liquid.blocks.${this.block}`, html);
// return html;
}
});
-3
View File
@@ -1,7 +1,4 @@
var Liquid = require('..');
var Promise = require('any-promise');
var lexical = Liquid.lexical;
var re = new RegExp(`(${lexical.identifier.source})`);
module.exports = function(liquid) {
+1 -3
View File
@@ -30,9 +30,7 @@ module.exports = function(liquid) {
render: function(scope, hash) {
var collection = Liquid.evalExp(this.collection, scope) || [];
var html = '<table>',
promiseChain = Promise.resolve(''); // create an empty promise to begin the chain
length = collection.length;
var html = '<table>';
var offset = hash.offset || 0;
var limit = (hash.limit === undefined) ? collection.length : hash.limit;
-1
View File
@@ -1,5 +1,4 @@
var Liquid = require('..');
var lexical = Liquid.lexical;
module.exports = function(liquid) {
liquid.registerTag('unless', {
+1 -1
View File
@@ -37,7 +37,7 @@ describe('filters', function() {
it('should support ceil 3', () => test('{{ "3.5" | ceil }}', '4'));
it('should support ceil 4', () => test('{{ 183.357 | ceil }}', '184'));
it('should support date', function() {
it('should support date: %a %b %d %Y', function() {
str = ctx.date.toDateString();
return test('{{ date | date:"%a %b %d %Y"}}', str);
});
+16 -3
View File
@@ -74,15 +74,28 @@ describe('liquid', function() {
it('should render file', function() {
return engine.renderFile('/root/files/foo.html', ctx).should.eventually.equal('foo');
});
it('should render file relative to root', function() {
return engine.renderFile('files/foo.html', ctx).should.eventually.equal('foo');
it('should accept relative path', function() {
return expect(engine.renderFile('files/foo.html')).to.eventually.equal('foo');
});
it('should render file with context', function() {
return engine.renderFile('/root/files/name.html', ctx).should.eventually.equal('My name is harttle.');
});
it('should render file with default extname', function() {
it('should use default extname', function() {
return engine.renderFile('files/name', ctx).should.eventually.equal('My name is harttle.');
});
it('should accept root with no trailing slash', function(){
engine = Liquid({
root: '/root',
extname: '.html'
});
return expect(engine.renderFile('files/foo.html')).to.eventually.equal('foo');
});
it('should accept dot path', function(){
return expect(engine.renderFile('./files/foo.html')).to.eventually.equal('foo');
});
it('should accept double-dot path', function(){
return expect(engine.renderFile('files/foo/../foo.html')).to.eventually.equal('foo');
});
});
describe('#express()', function() {
it('should render templates', function() {