├── .gitignore ├── .gitmodules ├── .jshintrc ├── .npmignore ├── .travis.yml ├── History.md ├── LICENSE ├── Makefile ├── Readme.md ├── examples ├── app.js ├── color.js ├── require.js └── views │ └── index.jade ├── index.js ├── lib └── express-expose.js ├── package.json └── test ├── express-expose.test.js ├── fixtures ├── color.js ├── math.js └── math │ └── sub.js └── views └── index.jade /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # ------------------------------------------------------------------------------ 3 | # Common Node files and folders 4 | # https://github.com/github/gitignore/blob/master/Node.gitignore 5 | # ------------------------------------------------------------------------------ 6 | 7 | lib-cov 8 | *.seed 9 | *.log 10 | *.csv 11 | *.dat 12 | *.out 13 | *.pid 14 | *.gz 15 | 16 | pids 17 | logs 18 | results 19 | 20 | node_modules 21 | npm-debug.log 22 | 23 | 24 | # ------------------------------------------------------------------------------ 25 | # Nodemon 26 | # ------------------------------------------------------------------------------ 27 | 28 | .monitor 29 | 30 | 31 | # ------------------------------------------------------------------------------ 32 | # JSHint 33 | # ------------------------------------------------------------------------------ 34 | 35 | jshint 36 | 37 | 38 | # ------------------------------------------------------------------------------ 39 | # Numerous always-ignore extensions 40 | # ------------------------------------------------------------------------------ 41 | 42 | *.diff 43 | *.err 44 | *.orig 45 | *.rej 46 | *.swo 47 | *.swp 48 | *.vi 49 | *~ 50 | *.sass-cache 51 | 52 | 53 | # ------------------------------------------------------------------------------ 54 | # Files from other repository control systems 55 | # ------------------------------------------------------------------------------ 56 | 57 | .hg 58 | .svn 59 | .CVS 60 | 61 | 62 | # ------------------------------------------------------------------------------ 63 | # Your ideas 64 | # ------------------------------------------------------------------------------ 65 | 66 | .idea 67 | 68 | 69 | # ------------------------------------------------------------------------------ 70 | # OS X and other IDE's folder attributes 71 | # ------------------------------------------------------------------------------ 72 | 73 | .DS_Store 74 | Thumbs.db 75 | .cache 76 | .project 77 | .settings 78 | .tmproj 79 | *.esproj 80 | nbproject 81 | *.sublime-project 82 | *.sublime-workspace 83 | 84 | 85 | # ------------------------------------------------------------------------------ 86 | # Dreamweaver added files 87 | # ------------------------------------------------------------------------------ 88 | 89 | _notes 90 | dwsync.xml 91 | 92 | 93 | # ------------------------------------------------------------------------------ 94 | # Komodo 95 | # ------------------------------------------------------------------------------ 96 | 97 | *.komodoproject 98 | .komodotools 99 | 100 | 101 | # ------------------------------------------------------------------------------ 102 | # Add your custom excludes below 103 | # ------------------------------------------------------------------------------ 104 | coverage/ 105 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/expressjs/express-expose/685ae6f1c43c0bf9bf3e87848fd2d6189964aa8c/.gitmodules -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "jasmine", 4 | "spyOn", 5 | "it", 6 | "console", 7 | "describe", 8 | "after", 9 | "before", 10 | "beforeEach", 11 | "waits", 12 | "waitsFor", 13 | "runs", 14 | "alert", 15 | "confirm", 16 | "Modernizr", 17 | "impress", 18 | "exports", 19 | "self", 20 | "define", 21 | "google" 22 | ], 23 | 24 | "node" : true, 25 | "es5" : false, 26 | "browser" : true, 27 | "jquery": true, 28 | 29 | "boss" : false, 30 | "curly": false, 31 | "debug": false, 32 | "devel": false, 33 | "eqeqeq": true, 34 | "evil": true, 35 | "forin": false, 36 | "immed": false, 37 | "laxbreak": true, 38 | "laxcomma": true, 39 | "newcap": true, 40 | "noarg": true, 41 | "noempty": false, 42 | "nonew": false, 43 | "nomen": false, 44 | "onevar": false, 45 | "plusplus": false, 46 | "regexp": false, 47 | "undef": true, 48 | "sub": true, 49 | "strict": false, 50 | "white": false, 51 | "asi": false, 52 | 53 | "expr": true 54 | } 55 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | support 2 | test 3 | examples 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | - "0.11" 5 | script: "npm run-script test-travis" 6 | after_script: "npm install coveralls@2 && cat ./coverage/lcov.info | coveralls" 7 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.3.3 / 2012-08-14 3 | ================== 4 | 5 | * fix request-level exposure. closes #26 [jonpacker] 6 | 7 | 0.3.2 / 2012-07-30 8 | ================== 9 | 10 | * fix 3x support now that locals.use() is gone. closes #22 11 | 12 | 0.3.0 / 2012-05-30 13 | ================== 14 | 15 | * Added Express 3.x support 16 | * Removed exposing entire modules 17 | * Changed default namespace to "app" 18 | 19 | 0.2.2 / 2012-02-09 20 | ================== 21 | 22 | * Fixed conditional assignment (use `window.`) [arlolra] 23 | 24 | 0.2.1 / 2012-01-18 25 | ================== 26 | 27 | * Fixed: support for 0.6.x 28 | 29 | 0.2.0 / 2011-04-20 30 | ================== 31 | 32 | * Added require implementation. Closes #3 33 | * Added `Date` serialization support 34 | 35 | 0.1.0 / 2011-04-08 36 | ================== 37 | 38 | * Added `{app,res}.exposeModule(path[, namespace[, name]])` 39 | 40 | 0.0.1 / 2010-01-03 41 | ================== 42 | 43 | * Initial release 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2012- TJ Holowaychuk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | test: 3 | @./node_modules/.bin/mocha \ 4 | --require should \ 5 | --ui exports 6 | 7 | .PHONY: test -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | > [!CAUTION] 2 | > **This repository is archived and no longer actively maintained.** 3 | > 4 | > We are no longer accepting issues, feature requests, or pull requests. 5 | > For additional support or questions, please visit the [Express.js Discussions page](https://github.com/expressjs/express/discussions). 6 | 7 | # express-expose 8 | 9 | [![NPM Version][npm-image]][npm-url] 10 | [![NPM Downloads][downloads-image]][downloads-url] 11 | [![Build Status][travis-image]][travis-url] 12 | [![Test Coverage][coveralls-image]][coveralls-url] 13 | 14 | Expose helpers and local variables to the client-side. 15 | 16 | 17 | ## Install 18 | 19 | ```bash 20 | npm install -S express-expose 21 | ``` 22 | 23 | ## Usage 24 | 25 | `express@4.x`: 26 | 27 | ```js 28 | var express = require('express'); 29 | var expose = require('express-expose'); 30 | app = expose(app); 31 | app.expose(...); 32 | ``` 33 | 34 | `express@3.x` and `express@2.x`: 35 | 36 | ```js 37 | var express = require('express'); 38 | var expose = require('express-expose'); 39 | app.expose(...); 40 | ``` 41 | 42 | 43 | ## Versions 44 | 45 | * `express@4.x` (use `express-expose` at `>= 0.3.4`) 46 | * `express@3.x` (use `express-expose` at `>= 0.2.3` and `<= 0.3.3`) 47 | * `express@2.x` (use `express-expose` at `<= 0.2.2`) 48 | 49 | 50 | ## Examples 51 | 52 | ### Exposing Objects 53 | 54 | A common use-case for exposing objects to the client-side would be exposing some properties, perhaps the express configuration. The call to `app.expose(obj)` below defaults to exposing the properties to `app.*`, so for example `app.views`, `app.title`, etc. 55 | 56 | ```js 57 | app.set('views', __dirname + '/views'); 58 | app.set('view engine', 'jade'); 59 | app.set('title', 'Example'); 60 | app.set('default language', 'en'); 61 | 62 | app.expose(app.settings); 63 | ``` 64 | 65 | Another use-case would be exposing helper methods, perhaps the same ones as you are currently exposing to templates. Below we expose the `math` object as utilities to our templates, as well as the client-side. Within a template we would call `add(1,2)`, and on the CS we would call `utils.add(1,2)`, since we have passed the namespace "utils". 66 | 67 | ```js 68 | var math = { add: function(a,b){ return a + b; } }; 69 | app.expose(math, 'utils').helpers(math); 70 | ``` 71 | 72 | Sometimes you might want to output to a different area, so for this we can pass an additional param "languages" which tells express which buffer to write to, which ends up providing us with the local variable "languages" in our template, where the default is "javascript". The "app" string here is the namespace. 73 | 74 | ```js 75 | app.expose({ en: 'English', fr: 'French' }, 'app', 'languages'); 76 | ``` 77 | 78 | You'll then want to output the default buffer (or others) to your template, in Jade this would look something like: 79 | 80 | ```jade 81 | script!= javascript 82 | ``` 83 | 84 | And in EJS: 85 | 86 | ```html 87 | 88 | ``` 89 | 90 | ### Raw JavaScript 91 | 92 | It is also possible to expose "raw" javascript strings. 93 | 94 | ```js 95 | app.expose('var some = "variable";'); 96 | ``` 97 | 98 | Optionally passing the destination buffer, providing us with the "head" local variable, instead of the default of "javascript". 99 | 100 | ```js 101 | app.expose('var some = "variable";', 'head'); 102 | ``` 103 | 104 | ### Exposing Functions 105 | 106 | Exposing a named function is easy too, simply pass it in with an optional buffer name for placement within a template much like above. 107 | 108 | ```js 109 | app.expose(function someFunction(){ 110 | return 'yay'; 111 | }, 'foot'); 112 | ``` 113 | 114 | ### Self-Calling Functions 115 | 116 | Another alternative is passing an anonymous function, which executes itself, creating a "wrapper" function. 117 | 118 | ```js 119 | app.expose(function(){ 120 | function notify() { 121 | alert('this will execute right away :D'); 122 | } 123 | notify(); 124 | }); 125 | ``` 126 | 127 | ### Request-Level Exposure 128 | 129 | Finally we can apply all of the above at the request-level as well, below we expose "app.current.user" as `{ name: 'tj' }`, for the specific request only. 130 | 131 | ```js 132 | app.get('/', function(req, res){ 133 | var user = { name: 'tj' }; 134 | res.expose(user, 'app.current.user'); 135 | res.render('index', { layout: false }); 136 | }); 137 | ``` 138 | 139 | 140 | ## License 141 | 142 | [MIT](LICENSE) 143 | 144 | [npm-image]: https://img.shields.io/npm/v/express-expose.svg?style=flat 145 | [npm-url]: https://npmjs.org/package/express-expose 146 | [travis-image]: https://img.shields.io/travis/expressjs/express-expose.svg?style=flat 147 | [travis-url]: https://travis-ci.org/expressjs/express-expose 148 | [coveralls-image]: https://img.shields.io/coveralls/expressjs/express-expose.svg?style=flat 149 | [coveralls-url]: https://coveralls.io/r/expressjs/express-expose?branch=master 150 | [downloads-image]: http://img.shields.io/npm/dm/express-expose.svg?style=flat 151 | [downloads-url]: https://npmjs.org/package/express-expose 152 | -------------------------------------------------------------------------------- /examples/app.js: -------------------------------------------------------------------------------- 1 | 2 | // $ npm install express jade 3 | 4 | /** 5 | * Module dependencies. 6 | */ 7 | 8 | var express = require('express') 9 | , expose = require('../') 10 | , app = express.createServer() 11 | , url = require('url'); 12 | 13 | app.set('views', __dirname + '/views'); 14 | app.set('view engine', 'jade'); 15 | app.set('title', 'Example'); 16 | app.set('default language', 'en'); 17 | 18 | // expose all the settings to the client-side, 19 | // with "express" as the default namespace. 20 | // for example "express.title == 'Example'" 21 | app.expose(app.settings); 22 | 23 | // funtions are fine too, here we namespace as utils instead. 24 | // use as "utils.add(1,2);" 25 | 26 | // note that here we expose these functions as local variables 27 | // to the template, as well as the client. 28 | var math = { add: function(a,b){ return a + b; } }; 29 | app.expose(math, 'utils').helpers(math); 30 | 31 | app.expose({ sub: function(a,b){ return a - b; } }, 'express.utils'); 32 | 33 | // Sometimes you might want to output to a different area, 34 | // so for this we can pass an additional param "languages" 35 | // which tells express which buffer to write to, which ends 36 | // up providing us with the local variable "languages" 37 | app.expose({ en: 'English', fr: 'French' }, 'express', 'languages'); 38 | 39 | // we can also expose "raw" javascript 40 | // by passing a string 41 | app.expose('var some = "variable";'); 42 | 43 | // exposing a named function is easy too, simply pass it in 44 | // with an optional buffer param for placement within a template 45 | 46 | app.expose(function someFunction(){ 47 | return 'yay'; 48 | }, 'foot'); 49 | 50 | // another alternative is passing an anonymous function, 51 | // which executes itself, creating a "wrapper" function. 52 | 53 | app.expose(function(){ 54 | function notify() { 55 | alert('this will execute right away :D'); 56 | } 57 | notify(); 58 | }); 59 | 60 | // expose entire modules to retain their own scope is simple too, 61 | // simply pass the path, with optional namespace / buffer name. 62 | 63 | // the following exposes "color.dark()", "color.light()" etc by default 64 | // however we pass "utils.color" as a custom namespace. 65 | app.exposeModule(__dirname + '/color', 'utils.color'); 66 | 67 | app.get('/', function(req, res){ 68 | // we might want to expose some user 69 | // as the "express.current.user" global to the client 70 | var user = { name: 'tj' }; 71 | res.expose(user, 'express.current.user'); 72 | res.render('index', { layout: false }); 73 | }); 74 | 75 | app.listen(3000); 76 | console.log('listening on port 3000'); -------------------------------------------------------------------------------- /examples/color.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Parse `rgb` string, ex "#ff0000". 4 | */ 5 | 6 | var parseRGB = exports.parseRGB = function(rgb) { 7 | if ('#' == rgb[0]) rgb = rgb.substr(1); 8 | var rgb = parseInt(rgb, 16); 9 | return { 10 | r: (rgb & 0xff0000) >> 16 11 | , g: (rgb & 0x00ff00) >> 8 12 | , b: (rgb & 0x0000ff) 13 | } 14 | }; 15 | 16 | /** 17 | * Parse `rgb` string and return the lightness 18 | * value, aka an average of the max/min components. 19 | */ 20 | 21 | var lightness = exports.lightness = function(rgb){ 22 | rgb = parseRGB(rgb); 23 | var r = rgb.r / 255 24 | , g = rgb.g / 255 25 | , b = rgb.b / 255 26 | , min = Math.min(r,g,b) 27 | , max = Math.max(r,g,b); 28 | return (min + max) / 2 * 100; 29 | }; 30 | 31 | /** 32 | * Return true if the `rgb` string is light. 33 | */ 34 | 35 | exports.light = function(rgb) { 36 | return lightness(rgb) > 50; 37 | }; 38 | 39 | /** 40 | * Return true if the `rgb` string is dark. 41 | */ 42 | 43 | exports.dark = function(rgb) { 44 | return lightness(rgb) <= 50; 45 | }; -------------------------------------------------------------------------------- /examples/require.js: -------------------------------------------------------------------------------- 1 | 2 | // $ npm install express jade 3 | 4 | /** 5 | * Module dependencies. 6 | */ 7 | 8 | var express = require('express') 9 | , expose = require('../') 10 | , app = express.createServer() 11 | , url = require('url'); 12 | 13 | app.set('views', __dirname + '/views'); 14 | app.set('view engine', 'jade'); 15 | app.set('title', 'Example'); 16 | app.set('default language', 'en'); 17 | app.set('boot', new Date); 18 | 19 | // tell express-expose that we want to 20 | // use the commonjs module system, and 21 | // not namespacing 22 | app.exposeRequire(); 23 | 24 | // we can expose arrays as modules if we wish 25 | app.expose([function(){ return 'yay'; }], 'array'); 26 | 27 | // or regular objects, the functions are always 28 | // serialized appropriately 29 | app.expose(app.settings, 'settings'); 30 | app.expose({ add: function(a, b){ return a + b; }}, 'utils'); 31 | 32 | // by default the module name be the basename, so 33 | // "color" in this case, however we explicitly pass "utils/color" 34 | app.exposeModule(__dirname + '/color', 'utils/color'); 35 | 36 | app.get('/', function(req, res){ 37 | res.render('index', { layout: false }); 38 | }); 39 | 40 | app.listen(3000); 41 | console.log('listening on port 3000'); -------------------------------------------------------------------------------- /examples/views/index.jade: -------------------------------------------------------------------------------- 1 | html 2 | head 3 | title= settings.title 4 | script!= javascript 5 | body 6 | h1= settings.title 7 | - if (locals.languages) 8 | script!= languages 9 | - if (locals.foot) 10 | script!= foot -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = require('./lib/express-expose'); -------------------------------------------------------------------------------- /lib/express-expose.js: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | * express-expose 4 | * Copyright(c) 2011 TJ Holowaychuk 5 | * MIT Licensed 6 | */ 7 | 8 | /** 9 | * Module dependencies. 10 | */ 11 | 12 | var basename = require('path').basename; 13 | var extname = require('path').extname; 14 | var fs = require('fs'); 15 | 16 | /** 17 | * Default namespace. 18 | */ 19 | var _namespace = 'app'; 20 | 21 | /** 22 | * Default local variable name. 23 | */ 24 | var _name = 'javascript'; 25 | 26 | /** 27 | * Expose the given `obj` to the client-side, with 28 | * an optional `namespace` defaulting to "express". 29 | * 30 | * @param {Object|String|Function} obj 31 | * @param {String} namespace 32 | * @param {String} name 33 | * @return {HTTPServer} for chaining 34 | * @api public 35 | */ 36 | 37 | function expose(obj, namespace, name) { 38 | 39 | var app = this.app || this; 40 | var req = this.req; 41 | 42 | app._exposed = app._exposed || {}; 43 | 44 | // support second arg as name 45 | // when a string or function is given 46 | if ('string' === typeof obj || 'function' === typeof obj) { 47 | name = namespace || _name; 48 | } else { 49 | name = name || _name; 50 | namespace = namespace || _namespace; 51 | } 52 | 53 | // buffer string 54 | if ('string' === typeof obj) { 55 | this.js = this.js || {}; 56 | var buf = this.js[name] = this.js[name] || []; 57 | buf.push(obj); 58 | // buffer function 59 | } else if ('function' === typeof obj && obj.name) { 60 | this.expose(obj.toString(), name); 61 | // buffer self-calling function 62 | } else if ('function' === typeof obj) { 63 | this.expose(';(' + obj + ')();', name); 64 | // buffer object 65 | } else { 66 | this.expose(renderNamespace(namespace), name); 67 | this.expose(renderObject(obj, namespace), name); 68 | this.expose('\n'); 69 | } 70 | 71 | // locals 72 | function locals(req, res) { 73 | 74 | var appjs = app.exposed(name); 75 | var resjs = res.exposed(name); 76 | var js = ''; 77 | 78 | if (appjs || resjs) { 79 | js += '// app: \n' + appjs; 80 | js += '// res: \n' + resjs; 81 | } 82 | 83 | res.locals[name] = js; 84 | 85 | } 86 | 87 | 88 | // app level locals 89 | if (!req && !app._exposed[name]) { 90 | app._exposed[name] = true; 91 | app.use(function(req, res, next){ 92 | locals(req, res); 93 | next(); 94 | }); 95 | // request level locals 96 | } else if (req) { 97 | locals(req, this); 98 | } 99 | 100 | return this; 101 | } 102 | 103 | /** 104 | * Render the exposed javascript. 105 | * 106 | * @return {String} 107 | * @api private 108 | */ 109 | 110 | function exposed(name) { 111 | name = name || _name; 112 | this.js = this.js || {}; 113 | return this.js[name] 114 | ? this.js[name].join('\n') 115 | : ''; 116 | } 117 | 118 | /** 119 | * Render a namespace from the given `str`. 120 | * 121 | * Examples: 122 | * 123 | * renderNamespace('foo.bar.baz'); 124 | * 125 | * var foo = foo || {}; 126 | * foo.bar = foo.bar || {}; 127 | * foo.bar.baz = foo.bar.baz || {}; 128 | * 129 | * @param {String} str 130 | * @return {String} 131 | * @api private 132 | */ 133 | 134 | function renderNamespace(str) { 135 | 136 | var parts = []; 137 | var split = str.split('.'); 138 | var len = split.length; 139 | 140 | return str.split('.').map(function(part, i) { 141 | parts.push(part); 142 | part = parts.join('.'); 143 | return (i ? '' : 'window.') + part + ' = window.' + part + ' || {};'; 144 | }).join('\n'); 145 | } 146 | 147 | /** 148 | * Render `obj` with the given `namespace`. 149 | * 150 | * @param {Object} obj 151 | * @param {String} namespace 152 | * @return {String} 153 | * @api private 154 | */ 155 | 156 | function renderObject(obj, namespace) { 157 | return Object.keys(obj).map(function(key){ 158 | var val = obj[key]; 159 | return namespace + '["' + key + '"] = ' + string(val) + ';'; 160 | }).join('\n'); 161 | } 162 | 163 | /** 164 | * Return a string representation of `obj`. 165 | * 166 | * @param {Mixed} obj 167 | * @return {String} 168 | * @api private 169 | */ 170 | 171 | function string(obj) { 172 | if ('function' === typeof obj) { 173 | return obj.toString(); 174 | } else if (obj instanceof Date) { 175 | return 'new Date("' + obj + '")'; 176 | } else if (Array.isArray(obj)) { 177 | return '[' + obj.map(string).join(', ') + ']'; 178 | } else if ('[object Object]' === Object.prototype.toString.call(obj)) { 179 | return '{' + Object.keys(obj).map(function(key){ 180 | return '"' + key + '":' + string(obj[key]); 181 | }).join(', ') + '}'; 182 | } else { 183 | return JSON.stringify(obj); 184 | } 185 | } 186 | 187 | exports = module.exports = function(app) { 188 | app.expose = expose.bind(app); 189 | app.response.expose = expose; 190 | app.exposed = app.response.exposed = exposed; 191 | return app; 192 | }; 193 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-expose", 3 | "version": "0.3.4", 4 | "scripts": { 5 | "prepublish": "npm prune", 6 | "test": "NODE_ENV=test mocha --reporter spec --bail --check-leaks test/", 7 | "test-cov": "NODE_ENV=test istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/", 8 | "test-travis": "NODE_ENV=test istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/" 9 | }, 10 | "description": "Expose helpers and local variables to the client-side", 11 | "keywords": [ 12 | "express" 13 | ], 14 | "author": "TJ Holowaychuk ", 15 | "contributors": [ 16 | { 17 | "name": "TJ Holowaychuk", 18 | "email": "tj@vision-media.ca" 19 | }, 20 | { 21 | "name": "Nick Baugh", 22 | "email": "niftylettuce@gmail.com" 23 | } 24 | ], 25 | "devDependencies": { 26 | "express": "4.x", 27 | "mocha": "*", 28 | "istanbul": "*", 29 | "should": "*", 30 | "jade": "*", 31 | "supertest": "*" 32 | }, 33 | "main": "index", 34 | "repository": { 35 | "type": "git", 36 | "url": "https://github.com/visionmedia/express-expose.git" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/express-expose.test.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Module dependencies. 4 | */ 5 | 6 | var express = require('express'); 7 | var expose = require('../'); 8 | var assert = require('assert'); 9 | var should = require('should'); 10 | var vm = require('vm'); 11 | var request = require('supertest'); 12 | 13 | describe('expose', function() { 14 | 15 | it('test app.expose(name)', function() { 16 | 17 | var app = express(); 18 | app = expose(app); 19 | app.expose({ one: 1, two: 2, three: 3 }); 20 | app.expose({ title: 'My Site' }, 'app.settings'); 21 | app.expose({ add: function(a, b){ return a + b; } }, 'utils'); 22 | app.expose({ en: 'English' }, 'langs', 'langs'); 23 | 24 | var js = app.exposed(); 25 | var scope = {}; 26 | 27 | scope.window = scope; 28 | vm.runInNewContext(js, scope); 29 | scope.app.one.should.equal(1); 30 | scope.app.two.should.equal(2); 31 | scope.app.three.should.equal(3); 32 | 33 | scope.app.settings.title.should.equal('My Site'); 34 | scope.utils.add(1,5).should.equal(6); 35 | 36 | js = app.exposed('langs'); 37 | scope = {}; 38 | 39 | scope.window = scope; 40 | vm.runInNewContext(js, scope); 41 | scope.should.not.have.property('express'); 42 | scope.langs.en.should.equal('English'); 43 | 44 | }); 45 | 46 | it('test app.expose(str)', function() { 47 | 48 | var app = express(); 49 | app = expose(app); 50 | 51 | app 52 | .expose('var user = { name: "tj" };') 53 | .expose('var lang = "en";'); 54 | 55 | var js = app.exposed(); 56 | var scope = {}; 57 | 58 | vm.runInNewContext(js, scope); 59 | scope.lang.should.equal('en'); 60 | scope.user.name.should.equal('tj'); 61 | 62 | }); 63 | 64 | it('test app.expose(str, null, scope)', function() { 65 | 66 | var app = express(); 67 | app = expose(app); 68 | 69 | app 70 | .expose('var user = { name: "tj" };', 'foot') 71 | .expose('var lang = "en";'); 72 | 73 | var js = app.exposed(); 74 | var scope = {}; 75 | 76 | vm.runInNewContext(js, scope); 77 | scope.lang.should.equal('en'); 78 | scope.should.not.have.property('user'); 79 | 80 | js = app.exposed('foot'); 81 | vm.runInNewContext(js, scope = {}); 82 | scope.should.not.have.property('lang'); 83 | scope.user.name.should.equal('tj'); 84 | 85 | }); 86 | 87 | it('test app.expose(fn) self-calling function', function() { 88 | 89 | var app = express(); 90 | app = expose(app); 91 | 92 | var err; 93 | 94 | app.expose('var foo;'); 95 | app.expose(function(){ 96 | this.foo = 'bar'; 97 | var bar = 'bar'; 98 | }); 99 | 100 | app.expose('var name;', 'foot'); 101 | app.expose(function() { 102 | this.name = 'tj'; 103 | }, 'foot'); 104 | 105 | var js = app.exposed(); 106 | var scope = {}; 107 | 108 | vm.runInNewContext(js, scope); 109 | scope.foo.should.equal('bar'); 110 | scope.should.not.have.property('bar'); 111 | scope.should.not.have.property('name'); 112 | 113 | js = app.exposed('foot'); 114 | scope = {}; 115 | 116 | scope.window = scope; 117 | vm.runInNewContext(js, scope); 118 | scope.should.not.have.property('foo'); 119 | scope.name.should.equal('tj'); 120 | 121 | }); 122 | 123 | it('test app.expose(fn) named function', function() { 124 | 125 | var app = express(); 126 | app = expose(app); 127 | var err; 128 | 129 | app.expose(function add(a, b){ 130 | return a + b; 131 | }); 132 | 133 | app.expose(function sub(a, b){ 134 | return a - b; 135 | }, 'foot'); 136 | 137 | var js = app.exposed(); 138 | var scope = {}; 139 | 140 | scope.window = scope; 141 | vm.runInNewContext(js, scope); 142 | scope.add(1,3).should.equal(4); 143 | scope.should.not.have.property('sub'); 144 | 145 | js = app.exposed('foot'); 146 | scope = {}; 147 | 148 | scope.window = scope; 149 | vm.runInNewContext(js, scope); 150 | scope.sub(8,7).should.equal(1); 151 | scope.should.not.have.property('add'); 152 | 153 | }); 154 | 155 | it('test res.expose(str)', function(done) { 156 | 157 | var app = express(); 158 | app = expose(app); 159 | app.set('view engine', 'jade'); 160 | app.set('views', __dirname + '/views'); 161 | 162 | app.expose('var user = { name: "tj" };'); 163 | app.expose('user.id = 50;'); 164 | 165 | app.get('/', function(req, res) { 166 | res.expose('var lang = "en";'); 167 | res.expose('var country = "no";'); 168 | res.render('index'); 169 | }); 170 | 171 | request(app) 172 | .get('/') 173 | .end(function(err, res) { 174 | if (err) throw err; 175 | 176 | var scope = {}; 177 | vm.runInNewContext(res.text, scope); 178 | scope.user.name.should.equal('tj'); 179 | scope.user.id.should.equal(50); 180 | scope.country.should.equal('no'); 181 | scope.lang.should.equal('en'); 182 | done(); 183 | }); 184 | 185 | }); 186 | 187 | }); 188 | -------------------------------------------------------------------------------- /test/fixtures/color.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Parse `rgb` string, ex "#ff0000". 4 | */ 5 | 6 | var parseRGB = exports.parseRGB = function(rgb) { 7 | if ('#' == rgb[0]) rgb = rgb.substr(1); 8 | var rgb = parseInt(rgb, 16); 9 | return { 10 | r: (rgb & 0xff0000) >> 16 11 | , g: (rgb & 0x00ff00) >> 8 12 | , b: (rgb & 0x0000ff) 13 | } 14 | }; 15 | 16 | /** 17 | * Parse `rgb` string and return the lightness 18 | * value, aka an average of the max/min components. 19 | */ 20 | 21 | var lightness = exports.lightness = function(rgb){ 22 | rgb = parseRGB(rgb); 23 | var r = rgb.r / 255 24 | , g = rgb.g / 255 25 | , b = rgb.b / 255 26 | , min = Math.min(r,g,b) 27 | , max = Math.max(r,g,b); 28 | return (min + max) / 2 * 100; 29 | }; 30 | 31 | /** 32 | * Return true if the `rgb` string is light. 33 | */ 34 | 35 | exports.light = function(rgb) { 36 | return lightness(rgb) > 50; 37 | }; 38 | 39 | /** 40 | * Return true if the `rgb` string is dark. 41 | */ 42 | 43 | exports.dark = function(rgb) { 44 | return lightness(rgb) <= 50; 45 | }; -------------------------------------------------------------------------------- /test/fixtures/math.js: -------------------------------------------------------------------------------- 1 | 2 | exports.add = function(a, b){ 3 | return a + b; 4 | }; -------------------------------------------------------------------------------- /test/fixtures/math/sub.js: -------------------------------------------------------------------------------- 1 | 2 | // just kidding! 3 | exports.sub = function(a, b){ 4 | return require('../math').add(a, b); 5 | }; -------------------------------------------------------------------------------- /test/views/index.jade: -------------------------------------------------------------------------------- 1 | != javascript --------------------------------------------------------------------------------