Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
yukinying committed Nov 7, 2012
1 parent 938d6e8 commit ecaf9a4
Show file tree
Hide file tree
Showing 8 changed files with 328 additions and 1 deletion.
38 changes: 37 additions & 1 deletion README.md
Original file line number Original file line Diff line number Diff line change
@@ -1,2 +1,38 @@
connect-strictenjs connect-strictenjs
================== ==================

overview
--------

This is a connect middelware that adds ECMAScript 5 (ES5) strict mode by prepending "use strict" to all javascript blocks.
As developers do not need to modify the html or JS code that the server is serving, one could quickly test if their
code are compatible with the ES5 strict mode.

The package also comes with a code beautifier (based on UglifyJS2), which allows easier troubleshooting when syntax errors
are reported on minified code.

recommended usage
-----------------

Use it with the javascript testing framework that use connect. To enable the middleware, one should simply patch the
code with

```javascript
var strict = require('connect-strictenjs');

app = express();

app.use(strict.stricten() );
app.use(strict.beautifier());

// ... other logics that render the pages
```

Then install the package via

```shell
npm link
```

Sample code could be found in the example directory.

1 change: 1 addition & 0 deletions examples/html/helloworld.html
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1 @@
<script src=helloworld.js></script>
4 changes: 4 additions & 0 deletions examples/html/helloworld.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,4 @@
(function(){ console.log('hello world!'); document.write('hello world'); /* this is a quick and dirty... */ })();
var b = 2;
(function(){ b = 3; console.log("b ="+ b);})();
(function(){ a = 1; console.log("a ="+ a);})();
9 changes: 9 additions & 0 deletions examples/html/inline.html
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,9 @@



<script>
(function(){var k=13,d=4,j=0,a=document.documentElement,b=[a.className],f,c=navigator.plugins,g=k;if(c&&c.length){f=c["Shockwave Flash"];if(f&&f.description){j=parseInt(f.description.match(/\b(\d+)\.\d+\b/)[1],10)||0}}else{while(g--){try{new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+g);j=g;break}catch(h){}}}b.push("flash-"+j);while(j-->d){b.push("flash-gt"+j)}a.className=b.join(" ")})();
</script>

<script type="text/javascript">
rtTop = Number(new Date()); document.documentElement.className += ' jsenabled'; </script>
29 changes: 29 additions & 0 deletions examples/proxy.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,29 @@
var express = require('express');
var connect = require('connect');

var httpProxy = require('http-proxy')
var url = require('url');

// for development, use npm link to create symlink based installation.
var strict = require('connect-strictenjs');

var proxy = new httpProxy.RoutingProxy();

app = express();

var proxyware = function( req, res ) {
var uri = url.parse(req.url);
req.headers["Accept-Encoding"] = '';
proxy.proxyRequest(req, res, {
host: uri.hostname,
port: uri.port || 80
});
};

// app.use(express.logger());
app.use(connect.responseTime());
app.use(strict.stricten() );
app.use(strict.beautifier());
app.all('/*',proxyware);

app.listen(8080);
18 changes: 18 additions & 0 deletions examples/static.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,18 @@
var express = require('express');
var connect = require('connect');

var url = require('url');

// for development, use npm link to create symlink based installation.
var strict = require('connect-strictenjs');

app = express();

// app.use(express.logger());
app.use(connect.responseTime());
app.use(strict.stricten() );
app.use(strict.beautifier());

app.use(express.static(__dirname + '/html'));

app.listen(8080);
206 changes: 206 additions & 0 deletions lib/connect-stricten.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,206 @@
exports.filterJS = function( req, res ) {

// TODO don't test url.
return (
/\.js/.test(req.url)
&& req.accepts('json') == 'json'
&& res.statusCode == 200
) ;
}

exports.filterHTML = function( req, res ) {
return (
req.accepts('html') == 'html'
&& res.statusCode == 200
) ;
}

exports.beautify = function( body, p1, p2, p3 ) {
if( p3 ) body = p2;
try {
var U = require("uglify-js2");
var ostream = U.OutputStream({beautify: true, source_map: null} );
var toplevel = U.parse(body);
toplevel.print(ostream);
if( p3 )
return p1 + "\n" + ostream.toString() + "\n" + p3 ;
else
return ostream.toString();
} catch (e) {
console.log(body);
console.log(e)
}
return body;
}

exports.strictening = function( body, p1, p2, p3 ) {
if( p3 )
return p1 + "\n" + '"use strict";' + "\n" + p2 + "\n" + p3 ;
else
return '"use strict";' + "\n" + body;
}

exports.beautifier = function(options) {

var options = options || {} ;

return function (req, res, next) {

var
write = res.write
, writeHead = res.writeHead
, end = res.end
, url = req.originalUrl
, body = ''
, isJS = exports.filterJS(req,res)
, isHTML = exports.filterHTML(req,res)
;



res.on('header', function( ) {
if( isJS || isHTML ) {
console.log('Url is ' + req.url );
console.log('Content Length is ' + res.get('Content-Length'));
console.log('Content Type is ' + res.get('Content-Type'));

res.removeHeader('Content-Length');
res.removeHeader('last-modified');
}
if( res.get('Content-Type') ) {
isJS = isJS && /javascript|json/.test(res.get('Content-Type'));
}
});

// From https://github.com/nateps/connect/blob/4025c2fbd2f53d4a8fe5608055514eee0d696ca1/lib/patch.js
// Until connect has taken the patch, we could only patch it here.
res.writeHead = function(statusCode){
var reasonPhrase, headers, headerIndex;
if (typeof arguments[1] == 'string') {
reasonPhrase = arguments[1];
headerIndex = 2;
} else {
headerIndex = 1;
}
headers = arguments[headerIndex];
if (headers) {
for (var name in headers) {
this.setHeader(name, headers[name]);
}
}
if (!this._emittedHeader) this.emit('header');
this._emittedHeader = true;
return writeHead.call(this, statusCode, reasonPhrase);
};

res.write = function( chunk, encoding ) {
if( isJS || isHTML ) {
body += chunk; }
else {
write.apply(res,arguments);
}
}

res.end = function(chunk,encoding) {
if( isJS ) {
if (chunk) body += chunk;
console.log('beautifying ' + url);
var ubody = exports.beautify( body ) ;
write.call(res,ubody,encoding);
end.call(res);
} else if ( isHTML ) {
if (chunk) body += chunk;
console.log('beautifying ' + url);
body = body.replace(/(<script[^>]*>)((?:.|\s)*?)(<\/script>)/mig, exports.beautify ) ;
write.call(res,body,encoding);
end.call(res);

} else {
end.apply(res,arguments)
}
}

next();

};
}

exports.stricten = function(options) {

var options = options || {} ;

return function (req, res, next) {

var
called = false
, write = res.write
, writeHead = res.writeHead
, body = ''
, end = res.end
, url = req.originalUrl
, isJS = exports.filterJS( req, res)
, isHTML = exports.filterHTML( req, res)
;

// Normal case
res.on('header', function( ) {
if( isJS ) {
res.removeHeader('Content-Length');
res.removeHeader('last-modified'); // do not cache modification on-the-fly
}
if( res.get('Content-Type') ) {
isJS = isJS && /javascript|json/.test(res.get('Content-Type'));
}
});

// From https://github.com/nateps/connect/blob/4025c2fbd2f53d4a8fe5608055514eee0d696ca1/lib/patch.js
// Until connect has taken the patch, we could only patch it here.
res.writeHead = function(statusCode){
var reasonPhrase, headers, headerIndex;
if (typeof arguments[1] == 'string') {
reasonPhrase = arguments[1];
headerIndex = 2;
} else {
headerIndex = 1;
}
headers = arguments[headerIndex];
if (headers) {
for (var name in headers) {
this.setHeader(name, headers[name]);
}
}
if (!this._emittedHeader) this.emit('header');
this._emittedHeader = true;
return writeHead.call(this, statusCode, reasonPhrase);
};

res.write = function( chunk, encoding ) {

if( isJS ) {
called = true;
console.log('strictening ' + url);
write.call(res, exports.strictening(chunk), encoding);
} else if ( isHTML ) {
if (chunk) body += chunk;
} else {
write.apply(res,arguments);
}
}


res.end = function(chunk,encoding) {
if ( isHTML ) {
if (chunk) body += chunk;
console.log('strictening ' + url);
body = body.replace(/(<script[^>]*>)((?:.|\s)*?)(<\/script>)/mig, exports.strictening ) ;
write.call(res,body,encoding);
end.call(res);
} else {
end.apply(res,arguments)
}
}

next();

};
}
24 changes: 24 additions & 0 deletions package.json
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "connect-strictenjs",
"version": "0.0.1",
"description": "a Strict mode (ES5) enforcer via connect middleware",
"main": "lib/connect-stricten.js",
"directories": {
"example": "examples",
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git@github.com:yukinying/connect-strictenjs.git"
},
"keywords": [
"ES5",
"connect",
"strict"
],
"author": "Albert Yu",
"license": "BSD"
}

0 comments on commit ecaf9a4

Please sign in to comment.