├── view ├── tests │ ├── loading.dust │ ├── a │ │ ├── loading.dust │ │ └── b │ │ │ └── loading.dust │ ├── b │ │ └── loading.dust │ └── namespace.dust ├── jserve │ ├── public │ │ ├── favicon.ico │ │ ├── favicon.png │ │ └── jserve.css │ ├── error.html │ └── index.html └── test-runner.dust ├── .eslintignore ├── docs ├── diagram.png ├── shunter-logo.png ├── img │ ├── shunter-assets.png │ ├── shunter-backend-proxy.png │ └── shunter-json-intercept.png ├── migration │ ├── index.md │ ├── 3.0.md │ ├── 5.0.md │ ├── 4.0.md │ └── 2.0.md ├── middleware.md ├── web-api.md ├── output-filters.md ├── testing.md ├── sample-data.md ├── modules.md ├── input-filters.md ├── index.md ├── routing.md └── contributing-to-shunter.md ├── tests ├── .mocharc.json ├── server │ ├── mock-data │ │ └── logging │ │ │ └── transports │ │ │ ├── winston-syslog.js │ │ │ └── winston-console.js │ ├── mocks │ │ ├── each-module.js │ │ ├── glob.js │ │ ├── url.js │ │ ├── benchmark.js │ │ ├── logging.js │ │ ├── error-pages.js │ │ ├── dispatch.js │ │ ├── input-filter.js │ │ ├── watcher.js │ │ ├── log.js │ │ ├── http-proxy.js │ │ ├── router.js │ │ ├── request.js │ │ ├── os.js │ │ ├── cluster.js │ │ ├── processor.js │ │ ├── connect.js │ │ ├── response.js │ │ ├── dustjs-helpers.js │ │ ├── renderer.js │ │ ├── path.js │ │ ├── fs.js │ │ ├── mincer.js │ │ └── statsd.js │ ├── dust │ │ ├── lower.js │ │ ├── upper.js │ │ ├── strip-tags.js │ │ ├── title.js │ │ ├── amp.js │ │ ├── asset-path.js │ │ ├── html.js │ │ ├── trim.js │ │ ├── number-format.js │ │ ├── date-format.js │ │ ├── or.js │ │ └── and.js │ ├── integration │ │ ├── lib │ │ │ ├── http-request.js │ │ │ └── servers-under-test.js │ │ ├── do-not-blow-up-after-error.js │ │ └── smoke.js │ ├── core │ │ ├── content-type.js │ │ ├── benchmark.js │ │ ├── config.js │ │ ├── watcher.js │ │ ├── map-route.js │ │ ├── output-filter.js │ │ ├── renderer-whitespace.js │ │ ├── dispatch.js │ │ ├── router.js │ │ ├── dust.js │ │ ├── input-filter.js │ │ ├── logging.js │ │ ├── statsd.js │ │ └── error-pages.js │ ├── filters │ │ └── environment.js │ └── templates │ │ └── namespace.js ├── mock-app │ ├── resources │ │ ├── css │ │ │ ├── basic.css.scss │ │ │ └── main.css.ejs │ │ └── js │ │ │ └── main.js.ejs │ ├── data │ │ └── home.json │ ├── view │ │ └── home.dust │ └── app.js ├── helpers │ └── template.js └── client │ └── lib │ └── mocha.css ├── lib ├── shunter.js ├── benchmark.js ├── content-type.js ├── watcher.js ├── map-route.js ├── output-filter.js ├── input-filter.js ├── statsd.js ├── router.js ├── dust.js ├── logging.js ├── error-pages.js ├── worker.js ├── dispatch.js ├── server.js └── config.js ├── dust ├── lower.js ├── trim.js ├── upper.js ├── amp.js ├── strip-tags.js ├── title.js ├── number-format.js ├── html.js ├── date-format.js ├── and.js └── or.js ├── .gitignore ├── logging └── transports │ ├── winston-syslog.js │ └── winston-console.js ├── .editorconfig ├── public └── 500.html ├── .eslintrc ├── filters └── input │ └── environment.js ├── .github └── workflows │ └── test-on-push-and-pull.yml ├── package.json ├── bin ├── serve.js └── compile.js └── README.md /view/tests/loading.dust: -------------------------------------------------------------------------------- 1 | 2 | view/tests/loading.dust 3 | -------------------------------------------------------------------------------- /view/tests/a/loading.dust: -------------------------------------------------------------------------------- 1 | 2 | view/tests/a/loading.dust 3 | -------------------------------------------------------------------------------- /view/tests/b/loading.dust: -------------------------------------------------------------------------------- 1 | 2 | view/tests/b/loading.dust 3 | -------------------------------------------------------------------------------- /view/tests/a/b/loading.dust: -------------------------------------------------------------------------------- 1 | 2 | view/tests/a/b/loading.dust 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | tests/client/lib 3 | tests/mock-app/public/ 4 | -------------------------------------------------------------------------------- /docs/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springernature/shunter/HEAD/docs/diagram.png -------------------------------------------------------------------------------- /docs/shunter-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springernature/shunter/HEAD/docs/shunter-logo.png -------------------------------------------------------------------------------- /docs/img/shunter-assets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springernature/shunter/HEAD/docs/img/shunter-assets.png -------------------------------------------------------------------------------- /tests/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "recursive": true, 3 | "reporter": "spec", 4 | "timeout": "5000", 5 | "ui": "bdd" 6 | } -------------------------------------------------------------------------------- /view/jserve/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springernature/shunter/HEAD/view/jserve/public/favicon.ico -------------------------------------------------------------------------------- /view/jserve/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springernature/shunter/HEAD/view/jserve/public/favicon.png -------------------------------------------------------------------------------- /docs/img/shunter-backend-proxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springernature/shunter/HEAD/docs/img/shunter-backend-proxy.png -------------------------------------------------------------------------------- /docs/img/shunter-json-intercept.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springernature/shunter/HEAD/docs/img/shunter-json-intercept.png -------------------------------------------------------------------------------- /tests/server/mock-data/logging/transports/winston-syslog.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = 'This is not a function.'; 3 | -------------------------------------------------------------------------------- /tests/mock-app/resources/css/basic.css.scss: -------------------------------------------------------------------------------- 1 | $orange: #FFA500; 2 | 3 | .should-be-orange { 4 | background-color: $orange; 5 | } 6 | -------------------------------------------------------------------------------- /tests/server/mocks/each-module.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = sinon.stub(); 6 | -------------------------------------------------------------------------------- /tests/server/mocks/glob.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = { 6 | sync: sinon.stub() 7 | }; 8 | -------------------------------------------------------------------------------- /tests/server/mocks/url.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = { 6 | parse: sinon.stub() 7 | }; 8 | -------------------------------------------------------------------------------- /tests/server/mocks/benchmark.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = sinon.stub().returns(sinon.stub()); 6 | -------------------------------------------------------------------------------- /tests/server/mocks/logging.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = sinon.stub().returns({ 6 | getLogger: sinon.stub() 7 | }); 8 | -------------------------------------------------------------------------------- /tests/server/mocks/error-pages.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = sinon.stub().returns({ 6 | getPage: sinon.stub() 7 | }); 8 | -------------------------------------------------------------------------------- /lib/shunter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | process.env.TZ = 'UTC'; 4 | module.exports = require('./server'); 5 | module.exports.testhelper = require('../tests/helpers/template.js'); 6 | -------------------------------------------------------------------------------- /tests/server/mocks/dispatch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = sinon.stub().returns({ 6 | send: sinon.stub(), 7 | error: sinon.stub() 8 | }); 9 | -------------------------------------------------------------------------------- /tests/server/mocks/input-filter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = sinon.stub().returns({ 6 | add: sinon.stub(), 7 | run: sinon.stub() 8 | }); 9 | -------------------------------------------------------------------------------- /dust/lower.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = initFilter; 4 | 5 | function initFilter(dust) { 6 | dust.filters.lower = function (value) { 7 | return value.toLowerCase(); 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /dust/trim.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = initFilter; 4 | 5 | function initFilter(dust) { 6 | dust.filters.trim = function (value) { 7 | return value.toString().trim(); 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /dust/upper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = initFilter; 4 | 5 | function initFilter(dust) { 6 | dust.filters.upper = function (value) { 7 | return value.toUpperCase(); 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /tests/server/mocks/watcher.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = sinon.stub().returns({ 6 | watchTree: sinon.stub().returns({ 7 | on: sinon.stub() 8 | }) 9 | }); 10 | -------------------------------------------------------------------------------- /tests/server/mocks/log.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = { 6 | debug: sinon.spy(), 7 | info: sinon.spy(), 8 | warn: sinon.spy(), 9 | error: sinon.spy() 10 | }; 11 | -------------------------------------------------------------------------------- /dust/amp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = initFilter; 4 | 5 | function initFilter(dust) { 6 | dust.filters.amp = function (value) { 7 | return value.replace(/&(?![#a-z0-9]+?;)/g, '&'); 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /tests/mock-app/data/home.json: -------------------------------------------------------------------------------- 1 | { 2 | "layout": { 3 | "template": "home" 4 | }, 5 | "title": "Hello World!", 6 | "list": [ 7 | "foo", 8 | "bar", 9 | "baz" 10 | ] 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests/server/mocks/http-proxy.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = { 6 | createProxyServer: sinon.stub().returns({ 7 | web: sinon.stub(), 8 | on: sinon.stub() 9 | }) 10 | }; 11 | -------------------------------------------------------------------------------- /tests/server/mocks/router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = sinon.stub().returns({ 6 | map: sinon.stub().returns({ 7 | host: '127.0.0.1', 8 | port: 5401 9 | }) 10 | }); 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | .nyc_output 4 | *.iml 5 | *.log 6 | *.pid 7 | config/routes/*.json 8 | coverage/* 9 | min.js 10 | node_modules 11 | public/resources 12 | shunter-*.tgz 13 | tests/mock-app/public/ 14 | timestamp.json 15 | -------------------------------------------------------------------------------- /tests/mock-app/resources/css/main.css.ejs: -------------------------------------------------------------------------------- 1 | /* 2 | *= require basic.css 3 | */ 4 | 5 | body { 6 | font-family: Arial, Helvetica, sans-serif; 7 | text-align: center; 8 | color: #004f8b; 9 | background-color: #e0f1ff; 10 | } 11 | -------------------------------------------------------------------------------- /tests/server/mocks/request.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = { 6 | headers: { 7 | host: 'the.request.host' 8 | }, 9 | removeAllListeners: sinon.stub(), 10 | emit: sinon.stub() 11 | }; 12 | -------------------------------------------------------------------------------- /tests/server/mocks/os.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = { 6 | cpus: sinon.stub().returns([]), 7 | release: sinon.stub(), 8 | hostname: sinon.stub().returns('test-shunter.nature.com') 9 | }; 10 | -------------------------------------------------------------------------------- /tests/server/mocks/cluster.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = { 6 | isMaster: true, 7 | fork: sinon.stub().returns({ 8 | on: sinon.stub() 9 | }), 10 | workers: {}, 11 | on: sinon.stub() 12 | }; 13 | -------------------------------------------------------------------------------- /dust/strip-tags.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = initFilter; 4 | 5 | function initFilter(dust) { 6 | dust.filters.stripTags = function (value) { 7 | return value.replace(/<[^>]+>/g, ''); 8 | }; 9 | dust.filters.strip = dust.filters.stripTags; 10 | } 11 | -------------------------------------------------------------------------------- /tests/server/mocks/processor.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = sinon.stub().returns({ 6 | timestamp: sinon.stub(), 7 | intercept: sinon.stub(), 8 | proxy: sinon.stub(), 9 | ping: sinon.stub(), 10 | api: sinon.stub() 11 | }); 12 | -------------------------------------------------------------------------------- /tests/server/mocks/connect.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | var connect = sinon.stub().returns({ 6 | use: sinon.stub(), 7 | listen: sinon.stub() 8 | }); 9 | connect.utils = { 10 | error: sinon.stub().returns({}) 11 | }; 12 | 13 | module.exports = connect; 14 | -------------------------------------------------------------------------------- /dust/title.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = initFilter; 4 | 5 | function initFilter(dust) { 6 | dust.filters.title = function (value) { 7 | return value.replace(/\w+/g, function (txt) { 8 | return txt.charAt(0).toUpperCase() + txt.slice(1).toLowerCase(); 9 | }); 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /tests/server/mocks/response.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = function () { 6 | return { 7 | writeHead: sinon.stub(), 8 | write: sinon.stub(), 9 | getHeader: sinon.stub(), 10 | setHeader: sinon.stub(), 11 | end: sinon.stub() 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /tests/server/mocks/dustjs-helpers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = { 6 | render: sinon.stub(), 7 | compile: sinon.stub(), 8 | loadSource: sinon.stub(), 9 | makeBase: sinon.stub().returns({ 10 | push: sinon.stub().returnsArg(0) 11 | }), 12 | cache: {} 13 | }; 14 | -------------------------------------------------------------------------------- /docs/migration/index.md: -------------------------------------------------------------------------------- 1 | # Migration Guide 2 | 3 | Shunter's API changes between major versions. These guides are intended to help you make the switch when this happens. 4 | 5 | * [Migrating from 1.0 to 2.0](2.0.md) 6 | * [Migrating from 2.0 to 3.0](3.0.md) 7 | * [Migrating from 3.0 to 4.0](4.0.md) 8 | * [Migrating from 4.0 to 5.0](5.0.md) 9 | -------------------------------------------------------------------------------- /dust/number-format.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = initHelper; 4 | 5 | function initHelper(dust) { 6 | dust.helpers.numberFormat = function (chunk, context, bodies, params) { 7 | var num = context.resolve(params.num); 8 | if (num) { 9 | return chunk.write(num.replace(/\B(?=(\d{3})+(?!\d))/g, ',')); 10 | } 11 | return chunk.write(num); 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /tests/server/mock-data/logging/transports/winston-console.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var winston = require('winston'); 3 | 4 | var format = winston.format; 5 | 6 | module.exports = function () { 7 | return new (winston.transports.Console)({ 8 | format: format.combine( 9 | format.colorize(), 10 | format.timestamp() 11 | ), 12 | level: 'THIS_IS_FINE' 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /tests/mock-app/resources/js/main.js.ejs: -------------------------------------------------------------------------------- 1 | document.body.style.backgroundColor = randomValue([ 2 | '#fadbd1', 3 | '#e1f3c8', 4 | '#b6dff2' 5 | ]); 6 | 7 | function randomValue(array) { 8 | return array[randomBetween(0, array.length - 1)]; 9 | }; 10 | 11 | function randomBetween(min, max) { 12 | return Math.floor(Math.random() * (max - min + 1)) + min; 13 | }; 14 | 15 | -------------------------------------------------------------------------------- /tests/mock-app/view/home.dust: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |Hello world
' 11 | }, function (err, dom, str) { 12 | assert.strictEqual(str, 'Hello world'); 13 | done(); 14 | }); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /tests/server/dust/title.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | var assert = require('proclaim'); 5 | var helper = require('../../helpers/template.js')(); 6 | 7 | describe('Dust Filter: title', function () { 8 | it('Should be able to convert a string to title case', function (done) { 9 | helper.render('{test|title}', { 10 | test: 'hello this is SOME @test text' 11 | }, function (err, dom, str) { 12 | assert.strictEqual(str, 'Hello This Is Some @Test Text'); 13 | done(); 14 | }); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /tests/server/mocks/mincer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = { 6 | createServer: sinon.stub(), 7 | 8 | logger: { 9 | use: sinon.stub() 10 | }, 11 | 12 | Environment: function () { 13 | this.findAsset = sinon.stub(); 14 | this.registerHelper = sinon.stub(); 15 | this.appendPath = sinon.stub(); 16 | this.prependPath = sinon.stub(); 17 | }, 18 | Manifest: function () { 19 | this.assets = { 20 | 'test.css': 'test-prod-md5.css' 21 | }; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /logging/transports/winston-console.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var winston = require('winston'); 3 | 4 | var format = winston.format; 5 | 6 | var myFormat = format.printf(function (logformMessage) { 7 | return `${logformMessage.timestamp} - ${logformMessage.level}: ${logformMessage.message}`; 8 | }); 9 | 10 | module.exports = function (config) { 11 | return new winston.transports.Console({ 12 | format: winston.format.combine( 13 | format.colorize(), 14 | format.timestamp(), 15 | myFormat 16 | ), 17 | level: config.argv.logging 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /tests/server/dust/amp.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | var assert = require('proclaim'); 5 | var helper = require('../../helpers/template.js')(); 6 | 7 | describe('Dust Filter: amp', function () { 8 | it('Should safely html-escape ampersands', function (done) { 9 | helper.render('{test1|s|amp} {test2|s|amp}', { 10 | test1: 'A & B
', 11 | test2: 'A > & 舒 B &
' 12 | }, function (err, dom, str) { 13 | assert.strictEqual(str, 'A & B
A > & 舒 B &
'); 14 | done(); 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /tests/server/mocks/statsd.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var sinon = require('sinon'); 4 | 5 | module.exports = sinon.stub().returns({ 6 | timing: sinon.stub(), 7 | gauge: sinon.stub(), 8 | gaugeDelta: sinon.stub(), 9 | increment: sinon.stub(), 10 | decrement: sinon.stub(), 11 | histogram: sinon.stub(), 12 | set: sinon.stub(), 13 | classifiedTiming: sinon.stub(), 14 | classifiedGauge: sinon.stub(), 15 | classifiedGaugeDelta: sinon.stub(), 16 | classifiedIncrement: sinon.stub(), 17 | classifiedDecrement: sinon.stub(), 18 | classifiedHistogram: sinon.stub(), 19 | classifiedSet: sinon.stub(), 20 | buildMetricNameForUrl: sinon.stub() 21 | }); 22 | -------------------------------------------------------------------------------- /tests/server/dust/asset-path.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | var assert = require('proclaim'); 5 | var helper = require('../../helpers/template.js')(); 6 | 7 | describe('Dust Helper: assetPath', function () { 8 | it('Should render an asset path', function (done) { 9 | helper.render('{@assetPath src="test.css"/}', {}, function (err, dom, out) { 10 | assert.strictEqual('test.css', out); 11 | done(); 12 | }); 13 | }); 14 | 15 | it('Should render an asset path from a variable', function (done) { 16 | helper.render('{@assetPath src="{foo}.css"/}', {foo: 'test'}, function (err, dom, out) { 17 | assert.strictEqual('test.css', out); 18 | done(); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /dust/date-format.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dateformat = require('dateformat'); 4 | 5 | module.exports = initHelper; 6 | 7 | function initHelper(dust, renderer, config) { 8 | dust.helpers.dateFormat = function (chunk, context, bodies, params) { 9 | var date = null; 10 | var value = null; 11 | 12 | params = params || {}; 13 | 14 | try { 15 | value = (params.date) ? context.resolve(params.date) : null; 16 | date = (value) ? new Date(value.match(/^\d+$/) ? parseInt(value, 10) : value) : new Date(); 17 | chunk.write(dateformat(date, params.format || 'yyyy-mm-dd')); 18 | } catch (err) { 19 | config.log.error(err.message); 20 | } 21 | return chunk; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /tests/server/dust/html.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | var assert = require('proclaim'); 5 | var helper = require('../../helpers/template.js')(); 6 | 7 | describe('Dust Filter: html', function () { 8 | it('Should safely escape HTML entities', function (done) { 9 | helper.render('{test1|s|html} {test2|s|html}', { 10 | test1: '', 11 | test2: '舒 & && < >>> " < >' 12 | }, function (err, dom, str) { 13 | assert.strictEqual(str, '<script>alert("foo") && alert('bar');</script> 舒 & && < >>> " < >'); 14 | done(); 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /lib/content-type.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (url, opts) { 4 | opts = opts || {}; 5 | 6 | var ext = (url.includes('.')) ? url.split('.').pop().replace(/\?.*/, '') : null; 7 | 8 | var mapping = { 9 | atom: 'application/atom+xml', 10 | json: 'application/json', 11 | rss: 'application/rss+xml', 12 | rdf: 'application/rdf+xml', 13 | xml: 'application/xml', 14 | css: 'text/css', 15 | ris: 'application/x-research-info-systems', 16 | txt: 'text/plain' 17 | }; 18 | 19 | var mimetype = Object.prototype.hasOwnProperty.call(mapping, ext) ? mapping[ext] : 'text/html'; 20 | var charset = opts.charset ? '; charset=' + opts.charset : ''; 21 | return mimetype + charset; 22 | }; 23 | -------------------------------------------------------------------------------- /docs/migration/3.0.md: -------------------------------------------------------------------------------- 1 | # Shunter Migration Guide, 2.0 to 3.0 2 | 3 | This guide outlines how to migrate from Shunter 2.x to Shunter 3.x. It outlines breaking changes which might cause issues when you upgrade. 4 | 5 | ## Route Matching 6 | 7 | If you were using regular expressions to match routes against the url in the `routes.json` file, these now need to be delimited with `/` characters. 8 | 9 | Before: 10 | 11 | ```js 12 | { 13 | "localhost": { 14 | "^\\/path": { 15 | "host": "127.0.0.1", 16 | "port": 1337 17 | } 18 | } 19 | } 20 | ``` 21 | 22 | After: 23 | 24 | ```js 25 | { 26 | "localhost": { 27 | "/^\\/path/": { 28 | "host": "127.0.0.1", 29 | "port": 1337 30 | } 31 | } 32 | } 33 | ``` 34 | -------------------------------------------------------------------------------- /view/tests/namespace.dust: -------------------------------------------------------------------------------- 1 | 2 | 3 |