Comparar commits

...

666 Commits

Autor SHA1 Mensagem Data
TJ Holowaychuk d1d3f310e9 Release 3.0.0alpha1 2012-04-15 11:21:40 -07:00
TJ Holowaychuk 089a83363f Changed: enable "jsonp callback" as a default 2012-04-15 11:20:25 -07:00
TJ Holowaychuk c28e6db428 update mkdirp dep 2012-04-15 11:18:38 -07:00
TJ Holowaychuk 05253272cb clarify ejs example 2012-04-13 09:16:16 -07:00
TJ Holowaychuk 12e087820c Added: res.format() sets Vary: Accept 2012-04-12 20:11:15 -07:00
TJ Holowaychuk 8dc001567b removed res.cache()
too specific
2012-04-12 19:46:53 -07:00
TJ Holowaychuk 9af3256f72 added jsonp test 2012-04-11 20:27:21 -07:00
TJ Holowaychuk cdd333a2e0 connect 2.1.2 dep 2012-04-11 14:35:28 -07:00
TJ Holowaychuk aa4ec8f3e2 fixed glob example 2012-04-11 13:56:08 -07:00
TJ Holowaychuk 5ea78cf259 ocd 2012-04-11 13:50:41 -07:00
TJ Holowaychuk 600eaea2d1 fixed acceptance tests 2012-04-11 12:49:18 -07:00
TJ Holowaychuk 81b15833f7 connect 2.1.1 dep 2012-04-11 12:03:00 -07:00
TJ Holowaychuk 9abc221559 connect 2.1.0 dep 2012-04-11 11:17:29 -07:00
TJ Holowaychuk 7048be2830 refactoring auth example 2012-04-11 11:17:12 -07:00
TJ Holowaychuk 91eb27513a docs 2012-04-11 10:08:12 -07:00
TJ Holowaychuk 04f0682439 removed old benchmark target from Makefile 2012-04-11 09:57:43 -07:00
TJ Holowaychuk 36bab5408d removed old doc gen stuff from Makefile 2012-04-11 09:57:12 -07:00
TJ Holowaychuk c483dab4b8 ocd 2012-04-11 09:44:49 -07:00
TJ Holowaychuk f1d759f279 Merge pull request #1073 from Zoramite/lessMiddleware
Adding support back in for less CSS.
2012-04-11 08:32:45 -07:00
Randy Merrill 4c1afb2984 Making the default case for the dependencies be more dynamic. 2012-04-11 06:54:14 -07:00
Randy Merrill db9b2bfbe1 Adding support back in for less CSS. 2012-04-11 06:50:45 -07:00
TJ Holowaychuk 377677cf30 Merge branch 'master' of github.com:visionmedia/express 2012-04-10 12:19:51 -07:00
TJ Holowaychuk 24a4e95ffe Changed to allow extname or type/subtype only. Closes #1072 2012-04-10 12:19:34 -07:00
TJ Holowaychuk 8fdd9e967a Merge pull request #1069 from Benjen/patch-1
Updated example usage of res.locals() as it contained an error.
2012-04-05 08:54:16 -07:00
Benjen acfa6a692e Updated example usage of res.locals() as it contained an error. 2012-04-05 23:37:56 +08:00
TJ Holowaychuk 67ca22b6e4 throw when callback is not given to app.engine() 2012-04-04 12:30:25 -07:00
TJ Holowaychuk ba413ee98d added another res.redirect() example 2012-04-04 08:43:12 -07:00
TJ Holowaychuk acc0e934cb ocd 2012-04-02 20:13:50 -07:00
TJ Holowaychuk 1d485840fd ocd 2012-04-02 20:13:31 -07:00
TJ Holowaychuk dcb147608a ocd 2012-04-02 20:01:13 -07:00
TJ Holowaychuk ddf24d1fd6 fixed markdown example 2012-04-02 20:00:53 -07:00
TJ Holowaychuk 886d7e6903 Merge pull request #1066 from cpedros/patch-1
Unused require of fs module
2012-04-02 16:00:38 -07:00
TJ Holowaychuk 2079ccbf42 updated signed cookie tests 2012-04-02 16:00:23 -07:00
TJ Holowaychuk 5ec88b0f6c typo 2012-04-02 15:56:58 -07:00
TJ Holowaychuk b0bcd27124 removed req.signedCookie tests, this is connect 2012-04-02 15:56:40 -07:00
TJ Holowaychuk 4dfee21e91 removed req.cookies tests, this is connect 2012-04-02 15:56:21 -07:00
TJ Holowaychuk 18fa2c9c7d removed debug() for .use()
connect does this now
2012-04-02 15:54:19 -07:00
TJ Holowaychuk 04d43d60b7 added nicer error messages for failed view lookup. Closes #1065 2012-04-02 15:47:10 -07:00
Pero Pejovic 419731ec41 Unused require of fs module 2012-04-02 15:44:06 -07:00
TJ Holowaychuk 082ba88084 tabs -> spaces 2012-04-02 15:41:04 -07:00
TJ Holowaychuk 09a8474521 router: moved params logic to Router#match() 2012-04-02 15:39:20 -07:00
TJ Holowaychuk 6d323d3ff7 added param decoding test 2012-04-02 15:15:05 -07:00
TJ Holowaychuk c4e003518a Merge branch 'master' of github.com:visionmedia/express 2012-04-02 15:09:51 -07:00
TJ Holowaychuk 9e251d14af Removed Collection 2012-04-02 15:09:39 -07:00
TJ Holowaychuk 9abba7d69a ocd 2012-04-02 15:07:41 -07:00
TJ Holowaychuk 0377540e2d utils: added pathRegexp() 2012-04-02 15:07:25 -07:00
TJ Holowaychuk e6a15f66fc Merge pull request #1064 from ahizzle/master
(trivial) Give express init middleware function an explicit name
2012-03-30 15:19:14 -07:00
Andy Hiew 1787fd1b52 Trivial: Give the middleware init function an explicit name.
Middleware stack printout before:
    NODE> app.stack
    [ { route: '', handle: [Function: query] },
      { route: '', handle: [Function] },
      { route: '', handle: [Function: favicon] },
      { route: '', handle: [Function: logger] },

    Middleware stack printout after:
    NODE> app.stack
    [ { route: '', handle: [Function: query] },
      { route: '', handle: [Function: expressInit] },
      { route: '', handle: [Function: favicon] },
      { route: '', handle: [Function: logger] },
2012-03-30 16:05:11 -06:00
TJ Holowaychuk 54c3d5c113 reverse req.ips array 2012-03-29 16:39:32 -07:00
TJ Holowaychuk 6d0f9a37a2 req.ipds doesnt need "trust proxy"
not really anyway, if you use this
you better trust it :)
2012-03-29 16:36:36 -07:00
TJ Holowaychuk 60dac4d2ff Merge branch 'master' of github.com:visionmedia/express 2012-03-29 16:27:16 -07:00
TJ Holowaychuk dd468fbe9a Added req.ips 2012-03-29 16:26:59 -07:00
TJ Holowaychuk 04ecf04832 Added X-Forwarded-Proto support to req.secure 2012-03-29 16:17:44 -07:00
TJ Holowaychuk 6d45616a7a Merge pull request #1062 from shtylman/06d2016ee
remove unused variable
2012-03-29 08:58:48 -07:00
Roman Shtylman 06d2016ee7 remove unused variable from Router.route 2012-03-28 22:43:49 -04:00
TJ Holowaychuk 984bfadcdd Merge pull request #1057 from Skookum/master
Update Connect Version
2012-03-27 08:34:29 -07:00
Jim Snodgrass f79f3f8b22 update connect version 2012-03-27 12:11:48 -03:00
TJ Holowaychuk ba570a9842 typo 2012-03-24 11:42:26 -07:00
TJ Holowaychuk 365a98d00f docs 2012-03-24 11:39:47 -07:00
TJ Holowaychuk 4e2677fe2c docs 2012-03-24 11:37:26 -07:00
TJ Holowaychuk d6d16b7899 Added req.accepts() comma-delimited string support 2012-03-24 11:36:52 -07:00
TJ Holowaychuk 86a9e0803a refactored utils.accepts() 2012-03-24 11:32:28 -07:00
TJ Holowaychuk fdf96922b5 added res.json() array test to illustrate that it works 2012-03-24 11:13:53 -07:00
TJ Holowaychuk d396761f76 refactored cookie-sessions example 2012-03-23 18:22:30 -07:00
TJ Holowaychuk 711519361c fixed content-negotiation example 2012-03-23 18:11:12 -07:00
TJ Holowaychuk e4827b8d89 more docs for req.accepts(arr) 2012-03-23 18:03:19 -07:00
TJ Holowaychuk 7ec7cb94f9 Merge branch 'master' of github.com:visionmedia/express 2012-03-23 17:59:08 -07:00
TJ Holowaychuk 298899d02c Added array support. Closes #1053 2012-03-23 17:58:41 -07:00
TJ Holowaychuk 43b35a4ae0 Added array support. Closes #1053 2012-03-23 17:58:15 -07:00
TJ Holowaychuk a7a8dcd617 Added note to express(1) for running the app 2012-02-29 16:11:39 -08:00
TJ Holowaychuk bdf0b26a12 Added node app for npm scripts.start Closes #1032 2012-02-29 16:10:35 -08:00
TJ Holowaychuk 73e87b6a2e connect 2.0 dep 2012-02-27 19:31:27 -08:00
TJ Holowaychuk ac3d002cb2 added "view cache" in production test 2012-02-26 11:56:49 -08:00
TJ Holowaychuk ada2d0c627 added app.param() array test 2012-02-26 11:52:23 -08:00
TJ Holowaychuk 286d3a1ff8 added another app.param() test 2012-02-26 11:50:32 -08:00
TJ Holowaychuk 937f01a225 added app.param() tests 2012-02-26 11:46:44 -08:00
TJ Holowaychuk c9559e03da ignore coverage.html 2012-02-23 21:35:17 -08:00
TJ Holowaychuk d115798d5b ocd 2012-02-23 21:34:48 -08:00
TJ Holowaychuk b6ee5fafd0 Added mocha test coverage support 2012-02-23 20:49:50 -08:00
TJ Holowaychuk 533b31237c optimize res.format() 2012-02-23 10:59:54 -08:00
TJ Holowaychuk 812a470122 docs 2012-02-23 10:58:57 -08:00
TJ Holowaychuk eb3105ef25 Added extname support to res.format(). Closes #1024 2012-02-23 10:58:06 -08:00
TJ Holowaychuk ffcaa04d2c renamed res.respondTo() to res.format()
since you are not really responding with it,
its basically as switch
2012-02-22 19:59:52 -08:00
TJ Holowaychuk a47660ba67 refactored res.redirect() with respondTo() 2012-02-22 19:58:36 -08:00
TJ Holowaychuk e2291184dc changed DEBUG express:routes to express:router 2012-02-22 19:29:24 -08:00
TJ Holowaychuk 4e332452b7 Added req.subdomains 2012-02-22 16:36:13 -08:00
TJ Holowaychuk e2f43df5e9 refactored app.render() 2012-02-22 09:04:59 -08:00
TJ Holowaychuk 141929cd6e typo 2012-02-21 10:23:20 -08:00
TJ Holowaychuk ec03968bd4 added test for respondTo() callback args 2012-02-21 09:30:05 -08:00
TJ Holowaychuk a21435cb05 updated content-negotiation example 2012-02-18 17:37:47 -08:00
TJ Holowaychuk bdfa6d1fe7 Added: res.respondTo() defaults the content-type 2012-02-18 17:23:02 -08:00
TJ Holowaychuk b565e258cb Added res.respondTo(obj) 2012-02-18 17:13:40 -08:00
TJ Holowaychuk 892b605ab5 shorten --force desc 2012-02-18 15:35:07 -08:00
TJ Holowaychuk 4d99352526 Merge pull request #1016 from tstrimple/master
Added the ability to force the install of express scaffolding to a non-empty directory.
2012-02-18 15:34:34 -08:00
tstrimple cbf0eaa429 "Add the ability to force install express to non-empty directory." 2012-02-18 23:00:56 +00:00
TJ Holowaychuk 80e16c8ca3 tweak multipart example 2012-02-18 14:14:09 -08:00
TJ Holowaychuk 0ae024afa8 Merge branch 'integration' 2012-02-18 14:06:45 -08:00
TJ Holowaychuk 73caacbd42 mounting sucks, removing this example 2012-02-18 14:06:41 -08:00
TJ Holowaychuk b667bda8f2 y u no space? 2012-02-18 14:06:22 -08:00
TJ Holowaychuk 463e38cf67 y u no space? 2012-02-18 14:05:57 -08:00
TJ Holowaychuk 83c8d65e3d styling 2012-02-18 14:05:05 -08:00
TJ Holowaychuk 9548e7d1e2 removed hello world acceptance tests 2012-02-18 14:04:25 -08:00
TJ Holowaychuk ee290d82d1 fixing acceptance tests 2012-02-18 14:04:11 -08:00
TJ Holowaychuk b75bb003bd fixed markdown example 2012-02-18 13:54:36 -08:00
TJ Holowaychuk 6c2194fdb4 smaller hello world 2012-02-18 13:52:31 -08:00
TJ Holowaychuk da61d8b639 fixed github example 2012-02-18 13:52:02 -08:00
TJ Holowaychuk 863ba199f6 stack is always shown 2012-02-18 13:49:08 -08:00
TJ Holowaychuk 161ebb354f removed old flash example 2012-02-18 13:48:32 -08:00
TJ Holowaychuk 1516ebf7f9 misc 2012-02-18 13:46:22 -08:00
TJ Holowaychuk 2820f2227d fixing downloads example 2012-02-18 13:45:44 -08:00
TJ Holowaychuk a078f5f5c1 docs 2012-02-18 13:41:44 -08:00
TJ Holowaychuk d0a83053d3 fixed up blog example messages 2012-02-18 13:41:10 -08:00
TJ Holowaychuk b6bc01abde fixing blog example 2012-02-18 13:28:56 -08:00
TJ Holowaychuk 196a1eb6ad set view engine for auth app 2012-02-18 13:20:23 -08:00
TJ Holowaychuk 593271f536 removed accessLogger from auth example 2012-02-18 13:18:00 -08:00
TJ Holowaychuk 0f24f715ba tweak auth example 2012-02-18 13:16:17 -08:00
Robert Sköld bb9bfa5618 Cleaned out comments from resource acceptance test. 2012-02-18 13:08:26 -08:00
Robert Sköld 8120a06cd6 Updated resource example with acceptnce test. 2012-02-18 13:08:26 -08:00
Robert Sköld a153082120 Updated params example with acceptance test. 2012-02-18 13:08:26 -08:00
Robert Sköld 970031e267 Updated multipart example with acceptance test. 2012-02-18 13:08:26 -08:00
Robert Sköld a819856f3f Updated mounting example with acceptance test. 2012-02-18 13:08:26 -08:00
Robert Sköld 4dbaaa2855 Updated markdown example with acceptance test. 2012-02-18 13:08:26 -08:00
Robert Sköld 0593cf4379 Updated helloworld example with acceptance test. 2012-02-18 13:08:26 -08:00
Robert Sköld cd0e5dbb4c Updated format example with acceptance test. 2012-02-18 13:08:26 -08:00
Robert Sköld 7cb1c3cabb Updated form example for 3.x (not working as it relies on req.flash()) 2012-02-18 13:08:26 -08:00
Robert Sköld 550b9101b8 Updated error-pages example with acceptance test. 2012-02-18 13:08:26 -08:00
Robert Sköld 9d9564568b Updated error example with acceptance tests. 2012-02-18 13:08:26 -08:00
Robert Sköld 7ea7a53e7c Updated downloads example with acceptance tests. 2012-02-18 13:08:25 -08:00
Robert Sköld ac387caf21 Added acceptance test for cookies. 2012-02-18 13:08:25 -08:00
Robert Sköld ad3f1e84aa Updated blog example for Jade inheritence. Passes tests. 2012-02-18 13:08:25 -08:00
Robert Sköld 2432a0dda5 Added acceptance test for blog example. 2012-02-18 13:08:25 -08:00
Robert Sköld 03e5919910 Refactored acceptence/auth. 2012-02-18 13:08:25 -08:00
Robert Sköld 277e35f8c8 Added RegExp support to support/http for asserting the body. 2012-02-18 13:08:25 -08:00
Robert Sköld 0dd5836f3f Updated auth acceptance test style. 2012-02-18 13:08:25 -08:00
Robert Sköld 9290f0d407 Cookie secret is a cookieParser() thing. 2012-02-18 13:08:25 -08:00
Robert Sköld 9bd3ad846e Silence while NODE_ENV=test 2012-02-18 13:08:25 -08:00
Robert Sköld a8c73649ce Updated auth example for express 3.x. With a test. 2012-02-18 13:08:25 -08:00
TJ Holowaychuk 6368ab49b4 ocd 2012-02-18 12:59:22 -08:00
TJ Holowaychuk 16b6a64ef9 refactored express(1) package.json generation 2012-02-18 12:50:16 -08:00
TJ Holowaychuk e46431ee0e ws 2012-02-18 12:47:31 -08:00
TJ Holowaychuk 2e4cf0aa5c update mime dep 2012-02-18 12:46:36 -08:00
TJ Holowaychuk 3f8a7f05e8 update commander dep 2012-02-18 12:46:26 -08:00
TJ Holowaychuk 3360613bcd Merge branch 'master' of github.com:visionmedia/express 2012-02-18 12:41:55 -08:00
TJ Holowaychuk f8a9cbe074 Added req.fresh and req.stale tests. Closes #998 2012-02-18 12:41:24 -08:00
TJ Holowaychuk 15f2e0c899 Merge pull request #1006 from eivindfjeldstad/router
Added support for arrays of paths
2012-02-17 08:42:39 -08:00
Tj Holowaychuk 6518e746c1 removed require "qs" as its no longer used. Closes #1014 2012-02-16 08:17:59 -08:00
Eivind Fjeldstad 38b046d6ad Added test for an array of paths 2012-02-12 16:26:32 +01:00
Eivind Fjeldstad 28d7750eda Added support for arrays of paths 2012-02-12 16:23:21 +01:00
Tj Holowaychuk e5fc85bddc moved a debug() down 2012-02-09 13:40:33 -08:00
Tj Holowaychuk 2a40571118 Added DEBUG=express:application support 2012-02-09 13:29:21 -08:00
Tj Holowaychuk f1aa57c57e more debug() 2012-02-09 13:15:45 -08:00
Tj Holowaychuk 0b876ece41 Added DEBUG=express:routes support 2012-02-09 13:12:13 -08:00
Tj Holowaychuk ca0bd1a0b5 Added "debug" dependency 2012-02-09 12:14:31 -08:00
Tj Holowaychuk 2d31b5df34 Removed "qs" dep, only connect has this now 2012-02-08 12:50:30 -08:00
Tj Holowaychuk 10f7ca0ebf upgrade deps 2012-02-08 12:03:25 -08:00
TJ Holowaychuk 85d6964874 Removed req.header(field) 2012-02-07 08:32:08 -08:00
TJ Holowaychuk 76fd462bcc Removed res.header(field, value) 2012-02-07 08:30:27 -08:00
TJ Holowaychuk c44f01879f utilize res.set() internally 2012-02-07 08:28:40 -08:00
TJ Holowaychuk fe27989a69 doc typo 2012-02-07 08:25:40 -08:00
TJ Holowaychuk b04f3eeede refactored req.xhr 2012-02-07 08:24:58 -08:00
TJ Holowaychuk 6ab61d023f docs 2012-02-07 08:21:32 -08:00
TJ Holowaychuk 4d87efc771 Added "trust proxy" setting 2012-02-07 08:19:30 -08:00
TJ Holowaychuk e47d368239 update node support docs 2012-02-07 04:55:38 -08:00
TJ Holowaychuk 5b1235addc replaced short contrib list with git-summary(1) output 2012-02-07 04:55:07 -08:00
TJ Holowaychuk 8c2c1240e1 removed old req.get() for now 2012-02-07 04:50:00 -08:00
TJ Holowaychuk 27e696b7b1 Added req.get() alias of req.header() 2012-02-07 04:49:12 -08:00
TJ Holowaychuk bfba98f532 Removed req.header() defaultValue support 2012-02-07 04:47:51 -08:00
TJ Holowaychuk 8de3ad50b2 refactored res.redirect() with req.protocol() 2012-02-07 04:43:35 -08:00
TJ Holowaychuk 2ba343d2b5 Added req.protocol() 2012-02-07 04:39:10 -08:00
TJ Holowaychuk ff92afa557 Added "json replacer" and "json spaces" settings. Closes #996 [credit to jed] 2012-02-07 03:30:34 -08:00
Tj Holowaychuk c3c0fb95a8 backported fix from 2.x for app.all() del method 2012-02-06 10:12:59 -08:00
Tj Holowaychuk bb56a094bb Added app.all() test 2012-02-06 10:07:49 -08:00
Tj Holowaychuk 2211943170 make express(1) generated deps * 2012-01-31 19:48:38 -08:00
TJ Holowaychuk 4eb8bc0857 Merge pull request #968 from peters/patch-1
Typo
2012-01-18 17:17:40 -08:00
Peter Rekdal Sunde fa51cb8d63 Typo 2012-01-19 02:14:30 +01:00
Tj Holowaychuk 706dec93a4 keywords 2012-01-17 09:51:49 -08:00
Tj Holowaychuk 7a32920448 Merge branch 'master' of github.com:visionmedia/express 2012-01-17 09:51:39 -08:00
Tj Holowaychuk 57a3899c1d removed connect-form dev dep 2012-01-17 09:51:27 -08:00
Tj Holowaychuk 374d159e0e update dependencies 2012-01-17 09:49:02 -08:00
TJ Holowaychuk 4f5a41b84f removed connect-form dep 2012-01-16 20:16:08 -08:00
TJ Holowaychuk a2f380fdd6 Merge pull request #955 from mmalecki/npm-test
Add `test` script
2012-01-08 17:08:10 -08:00
Maciej Małecki 301085e510 Add test script 2012-01-09 02:03:23 +01:00
TJ Holowaychuk af5b64a434 Merge pull request #951 from Raynos/patch-1
Gave the router a name.
2012-01-06 07:32:23 -08:00
Raynos fa088e37bc Gave the router a name. All the other connect middlewares are named functions. 2012-01-06 14:39:37 +00:00
Tj Holowaychuk 613bdc91e5 Merge branch 'master' of github.com:visionmedia/express 2012-01-02 08:28:40 -08:00
TJ Holowaychuk edfe50e713 Removed app.is() support 2011-12-30 15:10:51 -08:00
TJ Holowaychuk 26fb403ced Fixed req.is() with charsets 2011-12-30 15:04:41 -08:00
TJ Holowaychuk 014fb46449 Added req.is() tests 2011-12-30 15:01:34 -08:00
TJ Holowaychuk 144a88b109 Removed app.match() 2011-12-28 12:09:58 -07:00
TJ Holowaychuk 34c0d2509a test for route index state 2011-12-28 12:07:46 -07:00
TJ Holowaychuk a12a9e3fd9 tests for Router#match() 2011-12-28 12:03:50 -07:00
TJ Holowaychuk 8df73f3d83 renamed Router#_match() -> match() 2011-12-28 11:57:45 -07:00
TJ Holowaychuk 6dac874ff4 renamed Router#_route() -> route() 2011-12-28 11:55:11 -07:00
TJ Holowaychuk 81d25f6861 Merge branch 'feature/decouple-router' 2011-12-28 11:15:10 -07:00
TJ Holowaychuk c0c1975da6 decouple Router options. Closes #941 2011-12-28 11:14:57 -07:00
Tj Holowaychuk dd7af29103 mocha.opts 2011-12-20 17:37:06 -08:00
Tj Holowaychuk 85ea5f67f4 Merge branch 'master' of github.com:visionmedia/express 2011-12-20 13:33:14 -08:00
Tj Holowaychuk 8e3cb6174d added test for res.sendfile() content-type override 2011-12-20 13:32:39 -08:00
TJ Holowaychuk 6c01e9a43a Update bin/express 2011-12-20 08:33:54 -08:00
TJ Holowaychuk 6061670161 Merge pull request #939 from ksato9700/master
EOL style per platform
2011-12-20 08:33:12 -08:00
Ken Sato 7c66db2c45 Change the eol character based on platform type 2011-12-19 22:55:50 -08:00
TJ Holowaychuk 05e95ae55a misc 2011-12-18 07:41:08 -08:00
TJ Holowaychuk 416ad564d0 Added cookie-sessions example 2011-12-17 15:11:52 -08:00
TJ Holowaychuk 55f8f9bc42 added regression test for #847 2011-12-17 13:53:28 -08:00
TJ Holowaychuk 386a9e88b4 removed old tests 2011-12-17 13:43:51 -08:00
TJ Holowaychuk f6ca25edbe web-service acceptance tests 2011-12-17 12:44:55 -08:00
TJ Holowaychuk 1ea221aa4e fixed an acceptance test 2011-12-17 12:21:42 -08:00
TJ Holowaychuk d72a6666a1 removed ejs layout.ejs from express(1) 2011-12-17 12:16:52 -08:00
TJ Holowaychuk b69199f884 fixed express(1) jade tmpl inheritance 2011-12-17 12:15:12 -08:00
TJ Holowaychuk 65042c86a6 removed the use of .include.string() 2011-12-17 12:02:34 -08:00
TJ Holowaychuk d7dccfd56d removed the use of should.contain() 2011-12-17 12:02:11 -08:00
Tj Holowaychuk e60f4a5e1e Merge branch 'master' of github.com:visionmedia/express 2011-12-16 14:44:35 -08:00
Tj Holowaychuk fa3d4cbb23 move express(1) static() up
so people dont get confused when it receives sessions
2011-12-16 14:44:12 -08:00
TJ Holowaychuk 56d303ec09 Merge pull request #934 from siong1987/keywords
update keywords for search.npmjs.org
2011-12-15 09:10:09 -08:00
Teng Siong Ong 4600548b4d update keywords for search.npmjs.org 2011-12-15 11:06:08 -06:00
Tj Holowaychuk 7d24c2ba40 Fixed app.set() with undefined 2011-12-15 09:00:39 -08:00
Tj Holowaychuk b4ce57caec spec 2011-12-09 16:14:23 -08:00
Tj Holowaychuk 43c09b2eaa ejs test 2011-12-09 16:07:15 -08:00
Tj Holowaychuk b32fd0bee4 * dev deps 2011-12-09 15:55:41 -08:00
Tj Holowaychuk 3b6e96efa9 ejs tests 2011-12-09 15:29:09 -08:00
Tj Holowaychuk 29ef828b9c added first batch of acceptance tests for examples 2011-12-09 15:21:10 -08:00
Tj Holowaychuk 39ae443433 semi 2011-12-09 15:09:14 -08:00
Tj Holowaychuk c30c2f8d38 typo 2011-12-09 14:32:35 -08:00
Tj Holowaychuk 5757f875f2 Added X-Forwarded-Proto support to res.redirect(). Closes #927 2011-12-08 12:45:46 -08:00
Tj Holowaychuk e49c482a3f req.body takes precedence 2011-12-07 08:41:22 -08:00
Tj Holowaychuk a592d6c1aa misc 2011-12-06 16:53:05 -08:00
Tj Holowaychuk 88f154fecd Added support for .. in redirects as well 2011-12-06 16:44:15 -08:00
Tj Holowaychuk d7dfe3e812 expose router 2011-12-06 16:36:52 -08:00
Tj Holowaychuk 489265e3ca Added support for ./ in redirects 2011-12-06 16:32:48 -08:00
Tj Holowaychuk 3212a70a0c misc 2011-12-06 16:21:04 -08:00
Tj Holowaychuk 1cda0a96ca Removed redirect "home" 2011-12-06 16:13:42 -08:00
Tj Holowaychuk 83fb9f7548 removed a test 2011-12-06 16:12:42 -08:00
Tj Holowaychuk 43295289bf Removed app.redirect() 2011-12-06 16:04:06 -08:00
Tj Holowaychuk 0f72ca823b docs 2011-12-06 15:58:56 -08:00
Tj Holowaychuk 41786bc776 misc 2011-12-06 15:54:25 -08:00
Tj Holowaychuk cca5d7ebbf more tests 2011-12-06 15:53:17 -08:00
Tj Holowaychuk 43c8764465 Added relative redirect support. Closes #920 2011-12-06 15:50:08 -08:00
Tj Holowaychuk a1e325a2d9 use app.path() in res.redirect() 2011-12-06 15:40:17 -08:00
Tj Holowaychuk 17a831e32f app.path() 2011-12-06 15:36:44 -08:00
Tj Holowaychuk 2a13db3bb8 Added favicon() to express(1) generated app 2011-12-05 20:01:25 -08:00
Tj Holowaychuk eb5a73538a express(1) errorHandler() only in development
no longer acts as production error handling,
just implement that with custom middleware
2011-12-05 19:41:05 -08:00
Tj Holowaychuk 006a6c787b Added exports.{request,response} 2011-11-28 11:48:27 -08:00
Tj Holowaychuk c3d96df0f0 Added req.route test 2011-11-24 17:59:00 -08:00
Tj Holowaychuk 15e7218bc4 tests for app.get() inheritance. Closes #904 2011-11-24 15:27:09 -08:00
Tj Holowaychuk 28f32b9b8e Removed req.notify() 2011-11-24 15:12:25 -08:00
Tj Holowaychuk 1d0a56b673 removed uses of "root" 2011-11-24 14:33:23 -08:00
Tj Holowaychuk ad1424681b comment some tests 2011-11-24 14:31:42 -08:00
Tj Holowaychuk 87b991c076 removed "root" setting
screw it, no one will understand anyway
2011-11-24 14:27:28 -08:00
Tj Holowaychuk 5d593f26af .parent tests 2011-11-24 14:04:37 -08:00
Tj Holowaychuk 853c270fce more mounting tests 2011-11-24 13:51:04 -08:00
Tj Holowaychuk fcf34e0587 adding some mounting tests 2011-11-24 13:49:27 -08:00
Tj Holowaychuk b6611c8a3b Added: emit "mount" event on the app being mounted 2011-11-24 13:24:34 -08:00
Tj Holowaychuk aab08d774b Removed implementation of app.mounted(callback) 2011-11-24 13:20:10 -08:00
Tj Holowaychuk 321aa52384 Removed app.mounted(callback) 2011-11-24 13:19:53 -08:00
Tj Holowaychuk 1334a74ef1 misc refactoring 2011-11-24 12:50:19 -08:00
Tj Holowaychuk 19e3384bb1 Added test for res.sendfile() with non-GET. Closes #723 2011-11-24 12:34:47 -08:00
Tj Holowaychuk 6ae32fd596 docs 2011-11-24 12:22:59 -08:00
Tj Holowaychuk 4c316ba4ce refactored init middleware into its own file 2011-11-24 12:14:12 -08:00
Tj Holowaychuk f2719411b7 Added event emitter inheritance test 2011-11-24 12:10:08 -08:00
Tj Holowaychuk 11faf6684e Added travis.yml. Closes #903 2011-11-24 11:58:34 -08:00
Tj Holowaychuk 547d18ce46 merged 2011-11-23 10:39:02 -08:00
Tj Holowaychuk f183a81289 update mocha 2011-11-22 17:42:21 -08:00
TJ Holowaychuk e44c874cab Fixed parseQuality(), exclude q=0 2011-11-20 12:54:48 -08:00
TJ Holowaychuk 9c7380efe4 Added req.acceptsLanguage() 2011-11-20 12:53:01 -08:00
TJ Holowaychuk 5e071a2e4b Added req.acceptsCharset() 2011-11-20 12:51:27 -08:00
TJ Holowaychuk ff9b82c4f6 todo 2011-11-20 12:44:25 -08:00
TJ Holowaychuk a0d0ac6cff docs 2011-11-20 12:43:06 -08:00
TJ Holowaychuk b605a5de87 Changed: req.accepts() utilizing utils.accepts() 2011-11-20 12:42:06 -08:00
TJ Holowaychuk 36be2b0688 Added utils.accepts(type, str) 2011-11-20 12:41:12 -08:00
TJ Holowaychuk 376a5da705 Added req.accepts() tests 2011-11-20 12:24:05 -08:00
TJ Holowaychuk c25258b75c removed irrelevant extending-templates example 2011-11-20 12:17:29 -08:00
TJ Holowaychuk c685f3a294 docs 2011-11-20 12:16:04 -08:00
TJ Holowaychuk f63767af0e example error layout 2011-11-20 12:15:47 -08:00
TJ Holowaychuk 4fa9a2e54b fixed error-pages example 2011-11-20 12:13:24 -08:00
TJ Holowaychuk 68bc592a05 fixed error example 2011-11-20 12:03:45 -08:00
TJ Holowaychuk 543fe2f2a4 fixed ejs example 2011-11-20 11:59:10 -08:00
TJ Holowaychuk be52f38d8f fixed downloads example 2011-11-20 11:43:40 -08:00
TJ Holowaychuk 722a92f374 fixed cookies example 2011-11-20 11:33:06 -08:00
TJ Holowaychuk d771d06e19 docs 2011-11-20 11:29:08 -08:00
TJ Holowaychuk a5227191b5 fixed content-negotiation example 2011-11-20 11:28:12 -08:00
TJ Holowaychuk 499d3d6d78 Added req.acceptedCharsets 2011-11-19 22:16:16 -08:00
TJ Holowaychuk 2adf020753 tests 2011-11-19 22:13:07 -08:00
TJ Holowaychuk e8c373694c Added req.acceptedLanguages 2011-11-19 22:12:09 -08:00
TJ Holowaychuk a8fd8cb645 Added req.accepted 2011-11-19 22:08:26 -08:00
TJ Holowaychuk fd06084106 more tests 2011-11-19 21:49:20 -08:00
TJ Holowaychuk 285500488d Added parseAccepts() util 2011-11-19 21:47:22 -08:00
TJ Holowaychuk 29d4ffd089 renamed prev util to parseQuality() 2011-11-19 21:43:48 -08:00
TJ Holowaychuk fe5efa597b Added utils.parseAccepts(str) 2011-11-19 21:40:12 -08:00
TJ Holowaychuk b93629a903 updated mocha 2011-11-19 16:02:42 -08:00
Tj Holowaychuk 0c72940933 updated mocha 2011-11-17 07:52:32 -08:00
Tj Holowaychuk 96f5279e3e consider 20ms slow 2011-11-16 14:38:09 -08:00
Tj Holowaychuk 821fa10203 update mocha 2011-11-16 14:35:38 -08:00
Tj Holowaychuk 9082e74971 Added app.listen() as a shortcut for http.createServer(app).listen() 2011-11-11 17:22:25 -08:00
Tj Holowaychuk 7a7d77e7bd Removed toArray() util 2011-11-11 14:30:27 -08:00
Tj Holowaychuk ce2ec94e96 Added utils.escape(html) test 2011-11-11 14:29:23 -08:00
Tj Holowaychuk d56e5d6923 Added utils.flatten(arr) tests 2011-11-11 14:27:36 -08:00
Tj Holowaychuk 5221ecc055 utils.isAbsolute() tests 2011-11-11 14:26:43 -08:00
Tj Holowaychuk 6ac2c6f578 Added router next(err) test 2011-11-11 14:02:43 -08:00
Tj Holowaychuk 772b752fa5 Added more route matching tests 2011-11-11 14:01:10 -08:00
Tj Holowaychuk 3c002d08c2 fixed test due to HEAD change 2011-11-11 13:54:12 -08:00
Tj Holowaychuk 2876424240 Added optional app.head() support 2011-11-11 13:53:20 -08:00
Tj Holowaychuk 74a0177ec9 Added app.head() override test 2011-11-11 13:49:35 -08:00
Tj Holowaychuk da96844e9a Added app.head() test 2011-11-11 13:47:58 -08:00
Tj Holowaychuk 81652c8244 Added app.del() test 2011-11-11 13:46:44 -08:00
Tj Holowaychuk f17434c95b misc 2011-11-11 13:45:11 -08:00
Tj Holowaychuk 01e854b5d2 Added app.options() test 2011-11-11 13:44:42 -08:00
Tj Holowaychuk 42953c7c44 Fixed default OPTIONS behavior 2011-11-11 13:31:44 -08:00
Tj Holowaychuk 5e56446d26 Changed express.methods to include only those supported by node 2011-11-11 13:25:16 -08:00
Tj Holowaychuk 61652f4ad9 upper-case the name 2011-11-11 13:20:33 -08:00
Tj Holowaychuk fc1e84941d fixed head 2011-11-11 13:20:06 -08:00
Tj Holowaychuk 953eba0376 Added meta-generated tests for all HTTP methods supported 2011-11-11 13:18:50 -08:00
Tj Holowaychuk 5c032269e3 more tests 2011-11-11 13:04:08 -08:00
Tj Holowaychuk 1322d5a2c1 literal . test 2011-11-11 12:42:52 -08:00
Tj Holowaychuk 114f272906 escaped regexp test 2011-11-11 12:41:13 -08:00
Tj Holowaychuk 1286bbb982 naming capture groups 2011-11-11 12:36:16 -08:00
Tj Holowaychuk 9141c649e7 more tests 2011-11-11 12:34:09 -08:00
Tj Holowaychuk ff2242da31 tests for * 2011-11-11 12:32:14 -08:00
Tj Holowaychuk 730a419984 param single-segment test 2011-11-11 12:22:21 -08:00
Tj Holowaychuk 25bd7d7997 Added route regexp tests 2011-11-11 12:19:49 -08:00
Tj Holowaychuk 77c9d9207d Renamed "case sensitive routes" to "case sensitive routing"
to match "strict routing"
2011-11-11 12:14:35 -08:00
Tj Holowaychuk 1e77629f1f Added "strict routing" setting tests 2011-11-11 12:13:24 -08:00
Tj Holowaychuk 76f65456ab Added "case sensitive routes" tests 2011-11-11 12:10:38 -08:00
Tj Holowaychuk 26e20e7ae5 more routing tests 2011-11-11 12:06:30 -08:00
Tj Holowaychuk 96217cf3fe optional trailing slash 2011-11-11 12:05:18 -08:00
Tj Holowaychuk e9c96d8ccd tests for optional capture groups 2011-11-11 12:04:17 -08:00
Tj Holowaychuk 7ae2b968bb more routing tests 2011-11-11 11:54:56 -08:00
Tj Holowaychuk 83ea42afe5 started routing tests 2011-11-11 11:51:09 -08:00
Tj Holowaychuk 16587fcce1 Added req.param() default value test 2011-11-10 16:13:31 -08:00
Tj Holowaychuk ffded44f32 Added req.param() tests. Closes #885 2011-11-10 16:11:50 -08:00
Tj Holowaychuk 92c5284b80 fixed auto use(app.router) 2011-11-10 16:11:35 -08:00
Tj Holowaychuk f96102224c refactoring 2011-11-10 15:04:44 -08:00
Tj Holowaychuk bf87d626eb docs 2011-11-10 15:01:22 -08:00
Tj Holowaychuk e21a79dc61 Added res.cache() method 2011-11-10 15:00:50 -08:00
Tj Holowaychuk caec590fe1 Added res.cache(str) 2011-11-10 14:54:23 -08:00
Tj Holowaychuk 61ce6c59c2 misc 2011-11-10 14:48:00 -08:00
Tj Holowaychuk 205a1a14c7 Aded app.locals.use() precedence tests 2011-11-10 14:14:09 -08:00
Tj Holowaychuk 6709ab5f27 jade 0.17.x 2011-11-10 13:55:21 -08:00
Tj Holowaychuk 2d77279c94 Merge branch 'view-signature' 2011-11-10 13:42:14 -08:00
Tj Holowaychuk e9d7b6fbad Changed template engine signature to engine.__express(path, options, fn). Closes #878 2011-11-10 13:42:08 -08:00
Tj Holowaychuk 3e6171c7ff Fixed express(1) LF -> CRLF for windows. Closes #875 2011-11-10 12:29:49 -08:00
Tj Holowaychuk 04389fd6ff test for invalid cookie signature 2011-11-10 12:20:13 -08:00
Tj Holowaychuk a47b599048 Added req.signedCookies tests 2011-11-10 12:18:16 -08:00
Tj Holowaychuk 58eddd5ab4 Added res.signedCookie() and tests. Closes #880 2011-11-10 12:14:33 -08:00
Tj Holowaychuk 7ac857acef Added JSON cookie support & tests. Closes #879 2011-11-10 12:04:21 -08:00
Tj Holowaychuk e27b224933 make sure req/res protos are app-specific 2011-11-10 11:31:38 -08:00
Tj Holowaychuk 4f087df286 Added res proto mutation test 2011-11-10 11:29:35 -08:00
Tj Holowaychuk 87f6f6a3e3 Added app.request test 2011-11-10 11:25:54 -08:00
Tj Holowaychuk 94d1e94cf2 Added app.{request,response} 2011-11-10 11:21:24 -08:00
Tj Holowaychuk d249868e07 no longer manipulate the req/res protos directly 2011-11-10 11:18:43 -08:00
Tj Holowaychuk 429e48d873 Added app.locals.settings test 2011-11-10 08:36:18 -08:00
Tj Holowaychuk abb414c702 Added app.locals.use() arity < 3 test 2011-11-10 08:26:36 -08:00
Tj Holowaychuk 8f45dd4190 Added res.render() absolute path tests 2011-11-10 08:24:10 -08:00
Tj Holowaychuk d9098c5fcd more tests 2011-11-10 08:23:12 -08:00
Tj Holowaychuk b9dee730a8 Fixed app.render() absolute path support 2011-11-10 08:22:42 -08:00
Tj Holowaychuk 26c62a667f Added app.locals.use() test 2011-11-10 08:19:57 -08:00
Tj Holowaychuk 7d42ad00ff Removed "status" and "charset" options 2011-11-10 07:47:04 -08:00
Tj Holowaychuk 4a5776b513 more res.locals tests 2011-11-09 17:02:55 -08:00
Tj Holowaychuk f68ba2ef35 refactoring 2011-11-09 16:56:57 -08:00
Tj Holowaychuk a95a0ab5f9 using connects error code util 2011-11-09 16:27:48 -08:00
Tj Holowaychuk 30911f4a75 Added failing res.sendfile() test for 403 + callback 2011-11-09 16:14:38 -08:00
Tj Holowaychuk c9f184c8d5 Added res.sendfile() ENOENT test 2011-11-09 16:11:46 -08:00
Tj Holowaychuk 545f1fd07d Added first res.sendfile() callback test 2011-11-09 16:06:12 -08:00
Tj Holowaychuk 2f762265a8 Added forbidden tests 2011-11-09 16:03:42 -08:00
Tj Holowaychuk 7e6d8f39b4 Added res.sendfile() "root" setting test 2011-11-09 15:56:24 -08:00
Tj Holowaychuk bea74b7711 Fixed res.sendfile() 404s 2011-11-09 15:54:51 -08:00
Tj Holowaychuk 10e8dc57eb added failing res.sendfile() test on 404 2011-11-09 15:51:11 -08:00
Tj Holowaychuk f7b6dde086 refactored previous commit 2011-11-09 15:41:51 -08:00
Tj Holowaychuk 2fa36fa721 res.sendfile() tests 2011-11-09 15:39:53 -08:00
Tj Holowaychuk 40f8202402 utilize res.headerSent from connect 2011-11-09 15:38:48 -08:00
Tj Holowaychuk 4b0b55c1b7 misc refactoring 2011-11-09 15:33:54 -08:00
Tj Holowaychuk 0e395973c9 Added res.attachment() tests 2011-11-09 15:31:31 -08:00
Tj Holowaychuk 1f53cdb62d Added error in res.render() callback test 2011-11-09 15:21:38 -08:00
Tj Holowaychuk c32023d8ed Added "charset" option test 2011-11-09 15:17:44 -08:00
Tj Holowaychuk d2f98940d8 Added status option test 2011-11-09 15:15:55 -08:00
Tj Holowaychuk 536b16c7a9 Added res.render() callback with locals test 2011-11-09 15:11:07 -08:00
Tj Holowaychuk 9bfeae2df1 Added res.render() callback tests 2011-11-09 15:09:47 -08:00
Tj Holowaychuk 4d450ea25e local precedence tests 2011-11-09 15:04:52 -08:00
Tj Holowaychuk 84f01d1e30 Added res.render() tests 2011-11-09 15:00:40 -08:00
Tj Holowaychuk 1a5636b199 case sensitivity test 2011-11-08 20:29:48 -08:00
Tj Holowaychuk af46df7eae Removed req.isXMLHttpRequest
let me know if you actually use this :)
2011-11-08 20:28:55 -08:00
Tj Holowaychuk 801a1791d6 Added req.xhr tests 2011-11-08 20:28:06 -08:00
Tj Holowaychuk 333cf0b280 Added req.path test 2011-11-08 20:25:34 -08:00
Tj Holowaychuk 52e26697a9 Added index.<engine> render test 2011-11-08 20:22:27 -08:00
Tj Holowaychuk fdf620b688 more tests 2011-11-08 20:18:07 -08:00
Tj Holowaychuk 66f8ca52d6 Added app.engine() tests 2011-11-08 20:14:53 -08:00
Tj Holowaychuk f98c1127a6 Added app.render() local precedence test 2011-11-08 20:09:13 -08:00
Tj Holowaychuk 7e352fe28d Added app.render() app.locals test 2011-11-08 20:07:49 -08:00
Tj Holowaychuk d3b48e2fd5 Added more app.render() tests 2011-11-08 20:06:15 -08:00
Tj Holowaychuk 23159c094d Added app.render() tests 2011-11-08 20:00:03 -08:00
Tj Holowaychuk 2e22887f71 docs 2011-11-08 19:55:41 -08:00
Tj Holowaychuk c9b04b8be7 Added app.locals(obj) test 2011-11-08 19:54:46 -08:00
Tj Holowaychuk 2c0e13b513 Added res.locals(obj) test 2011-11-08 19:53:22 -08:00
Tj Holowaychuk 2937309f00 Added res.charset tests 2011-11-08 19:46:38 -08:00
Tj Holowaychuk 377056a33c Removed "charset" option 2011-11-08 19:44:16 -08:00
Tj Holowaychuk f42ce5be2b qs 0.3.2 to fix global var leak 2011-11-08 19:43:12 -08:00
Tj Holowaychuk ddeee9b6db Added req.query tests 2011-11-08 19:27:09 -08:00
Tj Holowaychuk 6bee32c174 removed a file i didnt mean to add :) 2011-11-08 19:18:25 -08:00
Tj Holowaychuk 11f55a06dd Added app.redirect() tests 2011-11-08 19:17:03 -08:00
Tj Holowaychuk 6a2d6b872b pending 2011-11-08 19:10:09 -08:00
Tj Holowaychuk d8787867c4 tweak test 2011-11-08 19:01:20 -08:00
Tj Holowaychuk 43d9f6ea17 tweak res.redirect() mount route logic 2011-11-08 18:59:40 -08:00
Tj Holowaychuk 1faba1302f tmp fix 2011-11-08 18:51:15 -08:00
Tj Holowaychuk 55ee0a0934 Added relative redirect test 2011-11-08 18:46:23 -08:00
Tj Holowaychuk 0653f73779 Added res.redirect() content-negotiation tests 2011-11-08 18:41:26 -08:00
Tj Holowaychuk 7a24021dc9 more res.redirect() tests 2011-11-08 18:40:01 -08:00
Tj Holowaychuk 9f2fe94484 Added res.redirect() test 2011-11-08 18:36:27 -08:00
Tj Holowaychuk a3950b5638 Added maxAge test 2011-11-08 18:33:00 -08:00
Tj Holowaychuk 8c03428279 Added res.cookie() options test 2011-11-08 18:30:48 -08:00
Tj Holowaychuk f4d7ea386d Added res.cookie() "root" setting test 2011-11-08 18:28:59 -08:00
Tj Holowaychuk bee0496cb1 Fixed res.cookie() path default 2011-11-08 18:28:22 -08:00
Tj Holowaychuk 5960b90efe Added res.cookie() tests 2011-11-08 18:27:18 -08:00
Tj Holowaychuk 0f2f3d4e29 Fixed res.clearCookie(), default path to "root" setting 2011-11-08 18:25:21 -08:00
Tj Holowaychuk bc673bef79 Added res.clearCookie() tests 2011-11-08 18:21:08 -08:00
Tj Holowaychuk 3fb7391b97 Added res.set(object) and res.set(field, value) tests 2011-11-08 18:15:31 -08:00
Tj Holowaychuk 442cd7515d Added res.type() test 2011-11-08 18:13:10 -08:00
Tj Holowaychuk a013ffe547 Added res.json(status, object) test 2011-11-08 17:57:25 -08:00
Tj Holowaychuk 835558229f refactored tests 2011-11-08 17:55:41 -08:00
Tj Holowaychuk dce23c79a1 Added res.json() tests 2011-11-08 17:54:36 -08:00
Tj Holowaychuk 4106bae79e generated helper test methods from express.methods 2011-11-08 17:47:47 -08:00
Tj Holowaychuk b756474d9d Added res.send() HEAD tests 2011-11-08 17:46:08 -08:00
Tj Holowaychuk b0c9209726 Added res.send() 304 / 204 tests 2011-11-08 17:44:05 -08:00
Tj Holowaychuk c96b778771 dot reporter 2011-11-08 17:40:41 -08:00
Tj Holowaychuk d0d721d80b Added res.send(Object) test 2011-11-08 17:40:20 -08:00
Tj Holowaychuk 7b50a78662 Added res.send(null || undefined) tests 2011-11-08 17:38:18 -08:00
Tj Holowaychuk aa869c637a Added res.send() content-type tests 2011-11-08 17:36:24 -08:00
Tj Holowaychuk f467fe1cbf Added res.send(Buffer) test 2011-11-08 17:34:04 -08:00
Tj Holowaychuk 15fd639cd9 Added res.send(String) test 2011-11-08 17:32:58 -08:00
Tj Holowaychuk f96f2cf56e Added res.send(code, body) test 2011-11-08 17:31:51 -08:00
Tj Holowaychuk b0f6278cea Added res.send(code) test 2011-11-08 17:30:29 -08:00
Tj Holowaychuk ae7bac9a6b Added res.header() chaining test 2011-11-08 17:29:01 -08:00
Tj Holowaychuk c8997204d4 Added res.header() tests 2011-11-08 17:27:05 -08:00
Tj Holowaychuk a2c51984a8 Added res.get(field) test 2011-11-08 17:25:05 -08:00
Tj Holowaychuk ed93e33d59 another test 2011-11-08 17:23:53 -08:00
Tj Holowaychuk 6e15b1cd20 Removed mock from res.status() test, mocks are lame 2011-11-08 17:23:14 -08:00
Tj Holowaychuk cc2513facf res.status(code) test 2011-11-08 17:18:44 -08:00
Tj Holowaychuk e303dcc915 multi-env configure() callbacks 2011-11-08 17:15:09 -08:00
Tj Holowaychuk 8ad17abb7b app.configure() tests 2011-11-08 17:13:16 -08:00
Tj Holowaychuk 5b296b5257 middleware tests
that dont quite work yet because node is being a PITA
2011-11-08 17:02:15 -08:00
Tj Holowaychuk 1a5c32f3ef setting up middleware tests 2011-11-08 16:00:44 -08:00
Tj Holowaychuk a15e745d42 test for application prototype 2011-11-08 15:45:30 -08:00
Tj Holowaychuk d17dd3e3d8 more config tests 2011-11-08 15:42:22 -08:00
Tj Holowaychuk 51a5c829bb config test 2011-11-08 15:40:34 -08:00
Tj Holowaychuk 8a91749e12 merged 2011-11-08 15:25:56 -08:00
Tj Holowaychuk 42fc0f9ee8 more tests 2011-11-08 15:23:02 -08:00
Tj Holowaychuk 17ccd55d11 upgrade should 2011-11-08 15:19:53 -08:00
Tj Holowaychuk b8a589d76f first new test 2011-11-08 15:19:19 -08:00
Tj Holowaychuk becf6d9413 Added mocha dev-dep 2011-11-08 15:07:31 -08:00
Tj Holowaychuk 9efc4b23dc Remove old tests 2011-11-08 15:05:47 -08:00
Tj Holowaychuk 6b1dc31759 version -pre so people are less confused 2011-11-04 09:06:45 -07:00
Tj Holowaychuk 9205d632cc Fixing express(1) for upcomming express 2011-11-04 09:06:23 -07:00
Tj Holowaychuk a751346b20 port some express(1) stuff from 2.x 2011-11-04 09:01:43 -07:00
Tj Holowaychuk 8111a19307 Removed sass.js support from express(1) 2011-11-04 08:36:09 -07:00
TJ Holowaychuk 860b4f1a3b Merge pull request #873 from gugu/master
Express depends on commander@0.0.4, which does not support node.js 5
2011-10-30 12:25:11 -07:00
Andrii Kostenko a5b1aa9ca7 Update package.json 2011-10-30 23:20:05 +04:00
Tj Holowaychuk 62257bce18 Added app.routes, replacing app.routes.all(). Closes #811 2011-10-14 17:51:23 -07:00
Tj Holowaychuk 0ed74aa68b added an array of routes 2011-10-14 17:48:57 -07:00
Tj Holowaychuk e0bd0d6470 Added app.get(setting). Closes #842 2011-10-14 17:37:23 -07:00
Tj Holowaychuk b433550556 refactored res.render() 2011-10-14 08:46:02 -07:00
Tj Holowaychuk 04ebd8875b Fixed express(1) public dir for windows. Closes #866 2011-10-14 08:38:33 -07:00
Tj Holowaychuk 1a1ed0ae45 semicolons 2011-10-13 09:46:48 -07:00
Tj Holowaychuk d6fabb6f8e move getters down 2011-10-13 09:46:26 -07:00
Tj Holowaychuk 08e8194db1 Merge branch 'master' of github.com:visionmedia/express 2011-10-13 09:45:59 -07:00
Tj Holowaychuk 0e4e050b21 Added req.fresh and req.stale
lame usage example:

app.get('/user/:id', function(req, res){
  var id = req.params.id;

  res.set('ETag', 'user-' + id);

  if (req.fresh) return res.send(304);
  setTimeout(function(){
    res.send('large expensive user response ' + id);
  }, 2000);
});
2011-10-13 09:43:31 -07:00
Tj Holowaychuk de17b285b1 Added req.secure 2011-10-11 09:45:01 -07:00
TJ Holowaychuk f640d0973d Merge pull request #863 from JonDum/master
Added JSHTML template engine for cli helper :)
2011-10-10 21:52:31 -07:00
Jonathan Dumaine 47ff0dc0cc Add JSHTML template engine for cli helper
JSHTML is a express compatible template engine 
with very nice syntax.

https://github.com/LuvDaSun/jshtml
2011-10-10 21:49:44 -07:00
Tj Holowaychuk 965e1d63dc added sync signature for app.locals.use() 2011-10-09 13:08:20 -07:00
Tj Holowaychuk 73f1da2ff7 Added replacement for dynamic locals. Closes #788 2011-10-09 13:01:32 -07:00
Tj Holowaychuk 0f6ad43e91 app.locals.use(fn) 2011-10-09 12:54:15 -07:00
Tj Holowaychuk 8d804a6c4a removed old app.locals() 2011-10-09 12:51:27 -07:00
Tj Holowaychuk 02f48aabbf map register function 2011-10-07 15:25:16 -07:00
Tj Holowaychuk d4b08e9566 misc 2011-10-07 15:18:00 -07:00
Tj Holowaychuk 9f1f58fd4b non-enumerable .router for Collection 2011-10-07 15:13:13 -07:00
Tj Holowaychuk 4ed92d50e0 misc refactoring 2011-10-07 15:12:24 -07:00
Tj Holowaychuk 8848004cb7 refactoring boot logic 2011-10-07 15:10:30 -07:00
Tj Holowaychuk 371b381074 more refactoring 2011-10-07 15:04:08 -07:00
Tj Holowaychuk 6d47011dcf View#contents() 2011-10-07 15:01:36 -07:00
Tj Holowaychuk 705cdb6368 misc refactoring 2011-10-07 15:00:20 -07:00
Tj Holowaychuk 90fc80fd87 docs 2011-10-07 14:59:42 -07:00
Tj Holowaychuk 041974ee01 added index lookup support back 2011-10-07 14:58:58 -07:00
Tj Holowaychuk 7369d861ca docs 2011-10-07 14:52:26 -07:00
Tj Holowaychuk e1da383aed new View 2011-10-07 14:51:06 -07:00
Tj Holowaychuk 6bcf29152f misc refactoring 2011-10-07 14:25:09 -07:00
Tj Holowaychuk 8a38211bd9 re-implemented "view cache" 2011-10-07 14:16:05 -07:00
Tj Holowaychuk cb2b9feb5f docs 2011-10-07 14:13:13 -07:00
Tj Holowaychuk c2d5d5619b lookup callback 2011-10-07 14:12:37 -07:00
Tj Holowaychuk 76b7d6975f app.lookup() 2011-10-07 14:11:08 -07:00
Tj Holowaychuk 7e9186d1ae removed hints setting 2011-10-07 14:08:06 -07:00
Tj Holowaychuk d1ce4c9923 req.query is always present 2011-10-07 14:04:59 -07:00
Tj Holowaychuk fed7fa4cd2 removed old parseRange util 2011-10-07 13:56:14 -07:00
Tj Holowaychuk 0d0125fc29 removed union util 2011-10-07 13:50:59 -07:00
Tj Holowaychuk 98e2c0522f merging res.locals 2011-10-07 13:50:31 -07:00
Tj Holowaychuk 294bc8c1d7 misc refactoring 2011-10-07 13:34:03 -07:00
Tj Holowaychuk ae11d83684 typo 2011-10-07 13:31:12 -07:00
Tj Holowaychuk aab9b08ec2 added charset option back 2011-10-07 13:30:33 -07:00
Tj Holowaychuk 31ff7db019 added status support back 2011-10-07 13:29:25 -07:00
Tj Holowaychuk c40c54fbee request-level render() 2011-10-07 13:27:43 -07:00
Tj Holowaychuk cecbaf2efe removed old view.js 2011-10-07 13:22:55 -07:00
Tj Holowaychuk e90413243e use app.engines instead of app.cache 2011-10-07 13:21:01 -07:00
Tj Holowaychuk a9396efeaf added app.register() 2011-10-07 13:19:29 -07:00
Tj Holowaychuk 60353c6d05 misc refactoring 2011-10-07 13:13:57 -07:00
Tj Holowaychuk 7b5ed50786 expose prototype 2011-10-07 13:13:32 -07:00
Tj Holowaychuk 02baa2b17c removed old http.js 2011-10-07 13:12:53 -07:00
Tj Holowaychuk d0585bd910 application.js 2011-10-07 13:10:15 -07:00
Tj Holowaychuk adf7124446 removed extra require() 2011-10-07 13:07:55 -07:00
Tj Holowaychuk 7710db4591 re-working view system 2011-10-07 13:07:19 -07:00
Tj Holowaychuk ce03cf49d8 uncommented old code 2011-10-07 10:01:30 -07:00
Tj Holowaychuk 65c0d14a4e expose connect middleware as express.* again 2011-10-07 10:00:10 -07:00
Tj Holowaychuk 667ed6fcf5 using connect.proto.use 2011-10-07 09:29:36 -07:00
Tj Holowaychuk d7da40642d removed old https inheritance logic 2011-10-07 09:24:17 -07:00
Tj Holowaychuk d6b5047511 setting up proto 2011-10-07 09:23:54 -07:00
Tj Holowaychuk 3b5a751b25 add connect repo as dep for now, since 2.0.0alpha blew everything up 2011-10-07 09:18:04 -07:00
Tj Holowaychuk 8a7491c97a "node":">= 0.5.0 < 0.7.0" 2011-10-05 15:08:50 -07:00
Tj Holowaychuk b3cab31cf7 connect 2.x dep 2011-10-05 15:04:43 -07:00
Tj Holowaychuk 021655a10a Added support for res.set(obj). Closes #834 2011-10-05 14:34:00 -07:00
Tj Holowaychuk e301d43704 Changed res.redirect() signature to accept status first. Closes #832
to match the others
2011-10-05 14:24:57 -07:00
Tj Holowaychuk 54c1a208c3 Added res.type() alias of res.contentType() 2011-09-28 10:27:13 -07:00
Tj Holowaychuk ad9bbda708 bench against loopback 2011-09-27 16:55:49 -07:00
Tj Holowaychuk 341e167eab comma last! 2011-09-21 15:35:30 -07:00
Tj Holowaychuk fb031d1ad5 Added mkdirp to express(1). Closes #795 2011-09-21 08:25:47 -07:00
Tj Holowaychuk d3937b9a61 Fixed res.redirect() HEAD support 2011-09-07 10:03:17 -07:00
Tj Holowaychuk 2c734e2e4c refactored res.send() 2011-09-07 10:02:27 -07:00
Tj Holowaychuk 77d8823261 misc refactoring 2011-09-06 15:19:05 -07:00
Tj Holowaychuk 6f85c14738 docs 2011-09-06 15:18:15 -07:00
Tj Holowaychuk edb1dc067a Fixed req.notify(), only escape args 2011-09-06 15:15:52 -07:00
Tj Holowaychuk 6b161d5389 Removed npm test script 2011-08-31 09:32:37 -07:00
Tj Holowaychuk c21e3feaa6 Fixed absolute path checking on windows. Closes #829 [reported by andrewpmckenzie] 2011-08-29 08:40:42 -07:00
Tj Holowaychuk a25ef01da3 Fixed multiple param callback regression. Closes #824 [reported by TroyGoode] 2011-08-22 10:05:16 -07:00
Tj Holowaychuk 0534266490 Merge branch 'master' of github.com:visionmedia/express 2011-08-22 10:05:13 -07:00
Tj Holowaychuk 71aca3c199 fixed some tests 2011-08-22 09:51:22 -07:00
TJ Holowaychuk 72fab80a74 Merge pull request #821 from pikeas/patch-1
Fixing typo: interacte -> interact
2011-08-21 10:40:42 -07:00
pikeas c8ab058842 Fixing typo: interacte -> interact 2011-08-22 16:11:15 +09:00
Tj Holowaychuk b166fd7d6e local -> localhost
most people wont have things set up the same as me
so this is probably not a good idea :D
2011-08-20 15:53:16 -07:00
Tj Holowaychuk 9545face97 mime 1.2.2 dep 2011-08-20 04:29:19 -07:00
Tj Holowaychuk 6dacd51b81 connect 1.6.2 dep 2011-08-20 04:28:48 -07:00
Tj Holowaychuk 571a182712 Added logger() to generated express(1) app 2011-08-20 04:02:33 -07:00
Tj Holowaychuk e3aabdc2bc Added make benchmark for experimental continuous-benchmarking tool 2011-08-20 03:19:59 -07:00
Tj Holowaychuk 4d8d5b12f2 Release 2.4.5 2011-08-19 10:18:57 -07:00
Tj Holowaychuk 5785e7e2e5 removed dynamicHelpers 2011-08-19 10:07:19 -07:00
Tj Holowaychuk 81f311105c removed app.helpers() use app.locals() 2011-08-19 10:05:47 -07:00
Tj Holowaychuk ad3679fcb8 haha... 2011-08-19 10:05:25 -07:00
Tj Holowaychuk 29508f1cc7 changed -css, --template to --stylus, --ejs
we can add more as we go
2011-08-18 17:25:32 -07:00
Tj Holowaychuk 426ba62348 rewrote express(1) to use commander.js 2011-08-18 17:21:39 -07:00
Tj Holowaychuk d2df055abe fixed res.sendfile() 404 support 2011-08-18 15:59:35 -07:00
Tj Holowaychuk d3ccdbcf72 build res.download() on top of res.sendfile()
like it should have always been
2011-08-18 15:43:19 -07:00
Tj Holowaychuk 7a476fc964 make res.sendfile() more like res.download(). Closes #774 2011-08-18 15:38:22 -07:00
Tj Holowaychuk 5da28be2b2 refactored res.sendfile() 2011-08-18 15:28:19 -07:00
Tj Holowaychuk 0932bdea30 OCD 2011-08-18 14:35:56 -07:00
Tj Holowaychuk 75054e17cf Refactored Route to use a single array of callbacks 2011-08-17 15:50:15 -07:00
Tj Holowaychuk 664907f02e fixed route error handlers when errors are thrown 2011-08-17 14:39:32 -07:00
Tj Holowaychuk f977272732 Added support for routes to handle errors. Closes #809
currently only the route end-point callbacks
support this, however this will change in the near future
to support route middleware etc
2011-08-17 14:33:23 -07:00
Tj Holowaychuk d10b7b43ea Added shorthand for the parsed request's pathname 2011-08-17 14:20:10 -07:00
Tj Holowaychuk e9abe1b846 Merged basepath setting. Closes #813 2011-08-17 10:13:25 -07:00
Tj Holowaychuk cc21f38664 qs >= 0.3.1 2011-08-17 07:53:45 -07:00
Tj Holowaychuk 34606c26f0 use nextRoute() internally 2011-08-16 18:30:01 -07:00
Tj Holowaychuk be9d66a574 Changed: removed .call(self) for route callbacks
not sure why we had this, ive never even used it
and the tests dont cover it, and its slower
2011-08-16 18:28:48 -07:00
Tj Holowaychuk ed9fcde499 Added app.routes.all(). Closes #803
not a huge fan of this API-wise, but at least it is something for now
2011-08-16 17:52:39 -07:00
Tj Holowaychuk 3c2139b0c3 Fixed res.redirect() on windows due to join() usage. Closes #808 2011-08-15 13:47:07 -07:00
Tj Holowaychuk 7eeec91ab5 russian docs 2011-08-14 09:36:07 -07:00
Tj Holowaychuk fdd43ee448 link to russian docs booyah! 2011-08-14 09:35:03 -07:00
Tj Holowaychuk ca75492512 Added support for multiple callbacks for app.param(). Closes #801
you can also make several calls to `app.param()` for the same
param name, which is equivalent to passing multiple in
a single call
2011-08-11 11:09:36 -07:00
Tj Holowaychuk a2a7644794 added another test 2011-08-11 10:12:22 -07:00
Tj Holowaychuk 91aebc758c Added test for app.param(fn) 2011-08-11 10:11:09 -07:00
Tj Holowaychuk ca0d29d811 expose list of http methods supported 2011-08-10 16:12:21 -07:00
Tj Holowaychuk c8c6aa2a1f Added res.get(field) as an alternative to res.header(field) 2011-08-10 14:15:37 -07:00
Tj Holowaychuk 19a1a22e63 Added res.set(field, val) as an alternative to res.header() 2011-08-10 14:13:36 -07:00
Tj Holowaychuk c729d62f89 another sidebar 2011-08-08 17:33:50 -07:00
Tj Holowaychuk 1793b50e6b sidebar example 2011-08-08 17:25:54 -07:00
Tj Holowaychuk 23dbe6a5f0 better layout control example 2011-08-08 17:15:13 -07:00
Tj Holowaychuk 509601e617 fixed app.locals precedence 2011-08-08 17:01:07 -07:00
Tj Holowaychuk d58beed752 Removed default local "app" 2011-08-08 16:51:41 -07:00
Tj Holowaychuk fd5d1076dc make req.notify() arity based 2011-08-08 16:45:22 -07:00
Tj Holowaychuk 05b76a1f93 prepping blog example for new express 2011-08-08 16:40:09 -07:00
Tj Holowaychuk f84ec803a4 use "dev" logger in blog example 2011-08-08 16:27:20 -07:00
Tj Holowaychuk c35cd7fcb7 Changed res.{send,json}() status code to the first arg at all times 2011-08-04 13:30:12 -07:00
Tj Holowaychuk bb9d50579b docs 2011-08-04 12:01:11 -07:00
Tj Holowaychuk 54d37512f5 Refactored res.header() 2011-08-03 20:00:39 -07:00
Tj Holowaychuk c516be8c4b added header.jade to jade example 2011-08-02 09:01:42 -07:00
Tj Holowaychuk 82c78ec8f9 semi 2011-07-29 11:02:50 -07:00
Tj Holowaychuk b1d4b71609 Refactored req.accepts() 2011-07-29 11:02:20 -07:00
Tj Holowaychuk 7440c7ddc7 more tests 2011-07-29 09:55:52 -07:00
Tj Holowaychuk 624dad5a78 Merge branch 'integration' 2011-07-29 09:40:18 -07:00
Arpad Borsos f4080210bd specialcase .:format routing to not include a dot in the capture group 2011-07-29 09:37:51 -07:00
Tj Holowaychuk c631eb43e3 Fixed 204 / 304 responses 2011-07-29 09:31:45 -07:00
Tj Holowaychuk 376bedf624 Changed res.send(null) responds with empty string
previously you would just get "null",
which is fine for res.json() but probably
not the best result for res.send()
2011-07-29 09:30:35 -07:00
Tj Holowaychuk 36e9c02f6f fixed a response test 2011-07-29 09:26:58 -07:00
Tj Holowaychuk 8f798569a8 fixed a jade test 2011-07-29 09:22:05 -07:00
Tj Holowaychuk 8c0e47baf9 more tests for routing 2011-07-27 09:02:31 -07:00
Tj Holowaychuk 461473e48e more tests 2011-07-27 09:00:53 -07:00
Tj Holowaychuk 8b1f109c1d renamed a test 2011-07-27 09:00:07 -07:00
Tj Holowaychuk e005cb31d8 Merge branch 'master' of github.com:visionmedia/express 2011-07-27 08:59:27 -07:00
Tj Holowaychuk 579836e221 docs 2011-07-27 08:58:58 -07:00
ctide b977ee6160 Fix the behavior for setting up routes with * in them. 2011-07-27 08:58:23 -07:00
TJ Holowaychuk ddce65b9dd Merge pull request #777 from purohit/master
Simple misspelling fix.
2011-07-25 17:59:57 -07:00
Ashwin Purohit e0e1105965 Fixing the misspelling of "manor" with "manner" in the 4 places it occurs. 2011-07-25 17:02:23 -07:00
Tj Holowaychuk 1f520f9f99 added express-resource to readme 2011-07-25 11:20:32 -07:00
Tj Holowaychuk 05a929deb6 tweak generated stylus 2011-07-25 11:15:15 -07:00
Tj Holowaychuk 5ac5352e33 Fixed [23]04 support 2011-07-22 08:35:33 -07:00
Tj Holowaychuk 787a555253 Added route-loading example for another route loading technique
using the vm module you can expose the route files at the root
level which IMO is nicer than module.exports = function(app){ etc
2011-07-20 12:33:53 -07:00
Tj Holowaychuk 388b84e858 node >= 0.4.9 < 0.7.0 for now 2011-07-19 16:14:48 -07:00
Tj Holowaychuk 7ffd17254a 3.0.0alpha1 soon
mainly so windows users can start playing
around with express, i will have a ton
of these alphas
2011-07-19 16:13:29 -07:00
Tj Holowaychuk 00affe187c update jade dev dep 2011-07-19 14:43:53 -07:00
Tj Holowaychuk 05844efbd6 qs >= 0.3.0 2011-07-19 12:08:39 -07:00
Tj Holowaychuk 3ab37028fc Removed req.flash() references
it will be req.notify(), req.session.notifications etc
2011-07-15 13:09:38 -07:00
Tj Holowaychuk 3a04888c5f docs 2011-07-15 12:12:46 -07:00
Tj Holowaychuk 6bd518241a refactored res.redirect() slightly 2011-07-15 11:56:39 -07:00
Tj Holowaychuk a3cddb856f Changed res.{cookie,clearCookie}() return res 2011-07-15 11:55:03 -07:00
Tj Holowaychuk 4b8e08d202 another req.is() example 2011-07-15 11:52:43 -07:00
Tj Holowaychuk 9413d30396 Added req.notify() alias of req.flash() 2011-07-15 11:36:52 -07:00
Tj Holowaychuk 5982fa63c6 refactored req.flash() 2011-07-15 11:36:02 -07:00
Tj Holowaychuk a4621a6418 refactored req.param() 2011-07-15 11:33:57 -07:00
Tj Holowaychuk 7eec21a5e6 examples 2011-07-15 11:31:47 -07:00
Tj Holowaychuk 96b72fe2f7 Renamed app.flashFormatters to app.formatters 2011-07-15 11:04:25 -07:00
Tj Holowaychuk c7c9606e87 Added %d flash formatter 2011-07-15 10:57:15 -07:00
Tj Holowaychuk 772c135d98 Merge branch 'remove-header-fields' 2011-07-15 10:52:17 -07:00
Tj Holowaychuk 365b3a76ba fixed tests 2011-07-15 10:52:11 -07:00
Tj Holowaychuk 41568b7f2a chainable res.header() 2011-07-15 10:47:38 -07:00
Tj Holowaychuk d853f6cf0e fixed some tests 2011-07-15 10:38:19 -07:00
Tj Holowaychuk bcfcce32d3 Removed header field support 2011-07-15 10:38:19 -07:00
Tj Holowaychuk 986916cf3e removed old dynamic helper logic from the view system 2011-07-15 10:31:52 -07:00
Tj Holowaychuk d689656775 precedence test 2011-07-15 10:30:51 -07:00
Tj Holowaychuk 8c56df7322 view system utilizing app.locals 2011-07-15 10:27:53 -07:00
Tj Holowaychuk 1dc87761a0 Changed app.locals to match res.locals 2011-07-15 10:13:21 -07:00
Tj Holowaychuk cd88b92587 Removed app.dynamicLocals(). Closes #756 2011-07-15 10:06:49 -07:00
Tj Holowaychuk eab03fdfc4 utilize connects new query() middleware 2011-07-15 10:03:46 -07:00
Tj Holowaychuk 9a8b86872d Replaced res.local[s]() with res.locals function. Closes #757 2011-07-15 10:01:31 -07:00
Tj Holowaychuk 04ce039ba4 Merge branch 'master' of github.com:visionmedia/express 2011-07-14 13:19:48 -07:00
Tj Holowaychuk 9605cbda45 misc 2011-07-14 12:59:14 -07:00
Tj Holowaychuk 3ec2739925 Removed "view options" setting. Closes #748 2011-07-14 12:59:14 -07:00
Tj Holowaychuk d250bf9b56 docs for previous commit 2011-07-14 12:59:14 -07:00
Tj Holowaychuk 6ebccb0518 Added "charset" option 2011-07-14 12:59:14 -07:00
Tj Holowaychuk b30efe4e2f misc refactoring 2011-07-14 12:59:14 -07:00
Tj Holowaychuk c275d279fc Added app.dynamicLocal(name, fn) 2011-07-14 12:59:14 -07:00
Tj Holowaychuk 7237a3c3b6 app.local() and res.local() return for chaining 2011-07-14 12:59:14 -07:00
Tj Holowaychuk f98896f6d7 Added app.local(name, val) 2011-07-14 12:59:14 -07:00
Tj Holowaychuk bcb2cdae4c app.helpers -> app.locals 2011-07-14 12:59:13 -07:00
Tj Holowaychuk 08159211a3 app.dynamicHelpers -> app.dynamicLocals 2011-07-14 12:59:13 -07:00
Tj Holowaychuk 232b6ab7ef Removed res.send() with no args support for 204
just use:

   res.send(204)
2011-07-14 12:59:13 -07:00
Tj Holowaychuk 3d2676d013 Removed res.helpers() alias of res.locals() 2011-07-14 12:59:13 -07:00
Tj Holowaychuk 477d06f990 removed old app.error() docs 2011-07-14 12:59:13 -07:00
Tj Holowaychuk ed19885ba1 removed old error handling docs 2011-07-14 12:59:13 -07:00
Tj Holowaychuk 297ae6fdb4 removed use of app.error() in examples 2011-07-14 12:59:13 -07:00
Tj Holowaychuk 456a985666 Removed app.error(). Closes #733
use trailing middleware with arity of 4 as
shown in this issue. They are functionally
equivalent
2011-07-14 12:59:13 -07:00
Tj Holowaychuk 261203d6c1 expresso 0.8.1 2011-07-14 12:59:13 -07:00
Dave Hoover 31262d2ea9 its is possessive, it's is shorthand for: it is 2011-07-14 12:59:13 -07:00
Tj Holowaychuk a8930b161e Fixed options.filename, exposing to template engines
this is useful for performing relative
lookups within the template engine itself,
without manually specifyin the path
2011-07-14 12:50:50 -07:00
Tj Holowaychuk fa31d45285 misc 2011-07-11 14:58:40 -07:00
Tj Holowaychuk 914e4a4cf7 Removed "view options" setting. Closes #748 2011-07-11 13:19:00 -07:00
Tj Holowaychuk f36d079f28 docs for previous commit 2011-07-11 13:12:55 -07:00
Tj Holowaychuk 17ddeef3ba Added "charset" option 2011-07-11 13:12:11 -07:00
Tj Holowaychuk f0c90ce668 misc refactoring 2011-07-11 12:53:52 -07:00
Tj Holowaychuk f19b312c48 Added app.dynamicLocal(name, fn) 2011-07-11 12:50:20 -07:00
Tj Holowaychuk e899a54ba7 app.local() and res.local() return for chaining 2011-07-11 12:46:10 -07:00
Tj Holowaychuk a4db994c2f Added app.local(name, val) 2011-07-11 12:43:31 -07:00
Tj Holowaychuk f98f46c836 app.helpers -> app.locals 2011-07-11 12:37:35 -07:00
Tj Holowaychuk 336aaaec9a app.dynamicHelpers -> app.dynamicLocals 2011-07-11 12:36:33 -07:00
Tj Holowaychuk b13ec8526e Removed res.send() with no args support for 204
just use:

   res.send(204)
2011-07-11 11:43:16 -07:00
Tj Holowaychuk 541020ff1b Removed res.helpers() alias of res.locals() 2011-07-11 11:22:25 -07:00
Tj Holowaychuk 9c153737b4 removed old app.error() docs 2011-07-11 11:18:29 -07:00
Tj Holowaychuk 7d53bb4064 removed old error handling docs 2011-07-11 11:18:15 -07:00
Tj Holowaychuk 4670751479 removed use of app.error() in examples 2011-07-11 11:13:07 -07:00
Tj Holowaychuk 8e058f16e4 Removed app.error(). Closes #733
use trailing middleware with arity of 4 as
shown in this issue. They are functionally
equivalent
2011-07-11 11:06:58 -07:00
Tj Holowaychuk f519f0a5b3 Merge branch 'master' of github.com:visionmedia/express 2011-07-11 11:02:10 -07:00
Tj Holowaychuk bb61304a49 expresso 0.8.1 2011-07-11 11:01:06 -07:00
TJ Holowaychuk 781d991eac Merge pull request #746 from redsquirrel/patch-1
typo
2011-07-09 13:24:17 -07:00
Dave Hoover d04c1f93a3 its is possessive, it's is shorthand for: it is 2011-07-09 13:19:15 -07:00
235 arquivos alterados com 8218 adições e 6741 exclusões
+6 -1
Ver Arquivo
@@ -1,3 +1,4 @@
coverage.html
.DS_Store
lib-cov
*.seed
@@ -9,5 +10,9 @@ lib-cov
*.swp
*.swo
benchmarks/graphs
testing.js
testing
node_modules/
testing
.coverage_data
cover_html
test.js
+1
Ver Arquivo
@@ -5,3 +5,4 @@ support/
test/
testing.js
.DS_Store
coverage.html
+3
Ver Arquivo
@@ -0,0 +1,3 @@
language: node_js
node_js:
- 0.6
+19
Ver Arquivo
@@ -1,4 +1,23 @@
2.4.5 / 2011-08-19
==================
* Added support for routes to handle errors. Closes #809
* Added `app.routes.all()`. Closes #803
* Added "basepath" setting to work in conjunction with reverse proxies etc. * Refactored `Route` to use a single array of callbacks
* Added support for multiple callbacks for `app.param()`. Closes #801
Closes #805
* Changed: removed .call(self) for route callbacks
* Dependency: `qs >= 0.3.1`
* Fixed `res.redirect()` on windows due to `join()` usage. Closes #808
2.4.4 / 2011-08-05
==================
* Fixed `res.header()` intention of a set, even when `undefined`
* Fixed `*`, value no longer required
* Fixed `res.send(204)` support. Closes #771
2.4.3 / 2011-07-14
==================
+12 -28
Ver Arquivo
@@ -1,35 +1,19 @@
DOCS = $(shell find docs/*.md)
HTMLDOCS =$(DOCS:.md=.html)
TESTS = $(shell find test/*.test.js)
REPORTER = dot
test:
@NODE_ENV=test ./node_modules/.bin/expresso \
-I lib \
$(TESTFLAGS) \
$(TESTS)
@NODE_ENV=test ./node_modules/.bin/mocha \
--reporter $(REPORTER)
test-cov:
@TESTFLAGS=--cov $(MAKE) test
test-acceptance:
@NODE_ENV=test ./node_modules/.bin/mocha \
--reporter spec \
test/acceptance/*.js
docs: $(HTMLDOCS)
@ echo "... generating TOC"
@./support/toc.js docs/guide.html
test-cov: lib-cov
@EXPRESS_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html
%.html: %.md
@echo "... $< -> $@"
@markdown $< \
| cat docs/layout/head.html - docs/layout/foot.html \
> $@
lib-cov:
@jscoverage lib lib-cov
site:
rm -fr /tmp/docs \
&& cp -fr docs /tmp/docs \
&& git checkout gh-pages \
&& cp -fr /tmp/docs/* . \
&& echo "done"
docclean:
rm -f docs/*.{1,html}
.PHONY: site test test-cov docs docclean
.PHONY: site test test-acceptance
+100 -65
Ver Arquivo
@@ -1,23 +1,20 @@
# Express
Insanely fast (and small) server-side JavaScript web development framework
built on [node](http://nodejs.org) and [Connect](http://github.com/senchalabs/connect).
var app = express.createServer();
app.get('/', function(req, res){
res.send('Hello World');
});
app.listen(3000);
![express logo](http://f.cl.ly/items/0V2S1n0K1i3y1c122g04/Screen%20Shot%202012-04-11%20at%209.59.42%20AM.png)
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
```js
var app = express.createServer();
app.get('/', function(req, res){
res.send('Hello World');
});
app.listen(3000);
```
## Installation
$ npm install express
or to access the `express(1)` executable install globally:
$ npm install -g express
## Quick Start
@@ -31,81 +28,55 @@ or to access the `express(1)` executable install globally:
Install dependencies:
$ npm install -d
$ npm install
Start the server:
$ node app.js
$ node app
## Features
* Built on [Connect](http://github.com/senchalabs/connect)
* Robust routing
* Redirection helpers
* Dynamic view helpers
* HTTP helpers (redirection, caching, etc)
* View system supporting 14+ template engines
* Content negotiation
* Focus on high performance
* View rendering and partials support
* Environment based configuration
* Session based flash notifications
* Built on [Connect](http://github.com/senchalabs/connect)
* High test coverage
* Executable for generating applications quickly
* Application level view options
* High test coverage
Via Connect:
## Philosophy
* Session support
* Cache API
* Mime helpers
* ETag support
* Persistent flash notifications
* Cookie support
* JSON-RPC
* Logging
* and _much_ more!
## Contributors
The following are the major contributors of Express (in no specific order).
* TJ Holowaychuk ([visionmedia](http://github.com/visionmedia))
* Ciaran Jessup ([ciaranj](http://github.com/ciaranj))
* Aaron Heckmann ([aheckmann](http://github.com/aheckmann))
* Guillermo Rauch ([guille](http://github.com/guille))
The Express philosophy is to provide small, robust tooling for HTTP servers. Making
it a great solution for single page applications, web sites, hybrids, or public
HTTP APIs.
Built on Connect you can use _only_ what you need, and nothing more, applications
can be as big or as small as you like, even a single file. Express does
not force you to use any specific ORM or template engine. With support for over
14 template engines via [Consolidate.js](github.com/visionmedia/consolidate.js) you
can quickly craft your perfect framework.
## More Information
* #express on freenode
* [express-expose](http://github.com/visionmedia/express-expose) expose objects, functions, modules and more to client-side js with ease
* [express-configure](http://github.com/visionmedia/express-configuration) async configuration support
* [express-messages](http://github.com/visionmedia/express-messages) flash notification rendering helper
* [express-namespace](http://github.com/visionmedia/express-namespace) namespaced route support
* [express-params](https://github.com/visionmedia/express-params) param pre-condition functions
* [express-mongoose](https://github.com/LearnBoost/express-mongoose) plugin for easy rendering of Mongoose async Query results
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
* Join #express on freenode
* [Google Group](http://groups.google.com/group/express-js) for discussion
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
* Visit the [Wiki](http://github.com/visionmedia/express/wiki)
* [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito)
* Screencast - [Introduction](http://bit.ly/eRYu0O)
* Screencast - [View Partials](http://bit.ly/dU13Fx)
* Screencast - [Route Specific Middleware](http://bit.ly/hX4IaH)
* Screencast - [Route Path Placeholder Preconditions](http://bit.ly/eNqmVs)
## Node Compatibility
Express 1.x is compatible with node 0.2.x and connect < 1.0.
Express 2.x is compatible with node 0.4.x and connect 1.x
* [Русскоязычная документация](http://express-js.ru/)
## Viewing Examples
First install the dev dependencies to install all the example / test suite deps:
$ npm install
$ cd express
$ npm install -d
then run whichever tests you want:
$ node examples/jade/app.js
$ node examples/content-negotiation
## Running Tests
@@ -117,11 +88,75 @@ then run the tests:
$ make test
## Contributors
```
project: express
commits: 3559
active : 468 days
files : 237
authors:
1891 Tj Holowaychuk 53.1%
1285 visionmedia 36.1%
182 TJ Holowaychuk 5.1%
54 Aaron Heckmann 1.5%
34 csausdev 1.0%
26 ciaranj 0.7%
21 Robert Sköld 0.6%
6 Guillermo Rauch 0.2%
3 Dav Glass 0.1%
3 Nick Poulden 0.1%
2 Randy Merrill 0.1%
2 Benny Wong 0.1%
2 Hunter Loftis 0.1%
2 Jake Gordon 0.1%
2 Brian McKinney 0.1%
2 Roman Shtylman 0.1%
2 Ben Weaver 0.1%
2 Dave Hoover 0.1%
2 Eivind Fjeldstad 0.1%
2 Daniel Shaw 0.1%
1 Matt Colyer 0.0%
1 Pau Ramon 0.0%
1 Pero Pejovic 0.0%
1 Peter Rekdal Sunde 0.0%
1 Raynos 0.0%
1 Teng Siong Ong 0.0%
1 Viktor Kelemen 0.0%
1 ctide 0.0%
1 8bitDesigner 0.0%
1 isaacs 0.0%
1 mgutz 0.0%
1 pikeas 0.0%
1 shuwatto 0.0%
1 tstrimple 0.0%
1 ewoudj 0.0%
1 Adam Sanderson 0.0%
1 Andrii Kostenko 0.0%
1 Andy Hiew 0.0%
1 Arpad Borsos 0.0%
1 Ashwin Purohit 0.0%
1 Benjen 0.0%
1 Darren Torpey 0.0%
1 Greg Ritter 0.0%
1 Gregory Ritter 0.0%
1 James Herdman 0.0%
1 Jim Snodgrass 0.0%
1 Joe McCann 0.0%
1 Jonathan Dumaine 0.0%
1 Jonathan Palardy 0.0%
1 Jonathan Zacsh 0.0%
1 Justin Lilly 0.0%
1 Ken Sato 0.0%
1 Maciej Małecki 0.0%
1 Masahiro Hayashi 0.0%
```
## License
(The MIT License)
Copyright (c) 2009-2011 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
Copyright (c) 2009-2012 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
+156 -194
Ver Arquivo
@@ -4,48 +4,52 @@
* Module dependencies.
*/
var fs = require('fs')
, exec = require('child_process').exec;
var express = require('../')
, exec = require('child_process').exec
, program = require('commander')
, mkdirp = require('mkdirp')
, os = require('os')
, fs = require('fs');
// CLI
program
.version(express.version)
.option('-s, --sessions', 'add session support')
.option('-e, --ejs', 'add ejs engine support (defaults to jade)')
.option('-J, --jshtml', 'add jshtml engine support (defaults to jade)')
.option('-c, --css <engine>', 'add stylesheet <engine> support (less|stylus) (defaults to plain css)')
.option('-f, --force', 'force on non-empty directory')
.parse(process.argv);
// Path
var path = program.args.shift() || '.';
// end-of-line code
var eol = 'win32' == os.platform() ? '\r\n' : '\n'
// Template engine
program.template = 'jade';
if (program.ejs) program.template = 'ejs';
if (program.jshtml) program.template = 'jshtml';
/**
* Framework version.
* Routes index template.
*/
var version = '2.4.3';
/**
* Add session support.
*/
var sessions = false;
/**
* CSS engine to utilize.
*/
var cssEngine;
/**
* Template engine to utilize.
*/
var templateEngine = 'jade';
/**
* Usage documentation.
*/
var usage = ''
+ '\n'
+ ' Usage: express [options] [path]\n'
+ '\n'
+ ' Options:\n'
+ ' -s, --sessions add session support\n'
+ ' -t, --template <engine> add template <engine> support (jade|ejs). default=jade\n'
+ ' -c, --css <engine> add stylesheet <engine> support (less|sass|stylus). default=plain css\n'
+ ' -v, --version output framework version\n'
+ ' -h, --help output help information\n'
;
var index = [
''
, '/*'
, ' * GET home page.'
, ' */'
, ''
, 'exports.index = function(req, res){'
, ' res.render(\'index\', { title: \'Express\' });'
, '};'
].join(eol);
/**
* Jade layout template.
@@ -57,23 +61,27 @@ var jadeLayout = [
, ' head'
, ' title= title'
, ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')'
, ' body!= body'
].join('\n');
, ' body'
, ' block content'
].join(eol);
/**
* Jade index template.
*/
var jadeIndex = [
'h1= title'
, 'p Welcome to #{title}'
].join('\n');
'extends layout'
, ''
, 'block content'
, ' h1= title'
, ' p Welcome to #{title}'
].join(eol);
/**
* EJS layout template.
* EJS index template.
*/
var ejsLayout = [
var ejsIndex = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
@@ -81,19 +89,37 @@ var ejsLayout = [
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' <%- body %>'
, ' <h1><%= title %></h1>'
, ' <p>Welcome to <%= title %></p>'
, ' </body>'
, '</html>'
].join('\n');
].join(eol);
/**
* EJS index template.
* JSHTML layout template.
*/
var ejsIndex = [
'<h1><%= title %></h1>'
, '<p>Welcome to <%= title %></p>'
].join('\n');
var jshtmlLayout = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
, ' <title> @write(title) </title>'
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' @write(body)'
, ' </body>'
, '</html>'
].join(eol);
/**
* JSHTML index template.
*/
var jshtmlIndex = [
'<h1>@write(title)</h1>'
, '<p>Welcome to @write(title)</p>'
].join(eol);
/**
* Default css template.
@@ -108,7 +134,7 @@ var css = [
, 'a {'
, ' color: #00B7FF;'
, '}'
].join('\n');
].join(eol);
/**
* Default less template.
@@ -123,19 +149,7 @@ var less = [
, 'a {'
, ' color: #00B7FF;'
, '}'
].join('\n');
/**
* Default sass template.
*/
var sass = [
'body'
, ' :padding 50px'
, ' :font 14px "Lucida Grande", Helvetica, Arial, sans-serif'
, 'a'
, ' :color #00B7FF'
].join('\n');
].join(eol);
/**
* Default stylus template.
@@ -143,11 +157,11 @@ var sass = [
var stylus = [
'body'
, ' padding 50px'
, ' font 14px "Lucida Grande", Helvetica, Arial, sans-serif'
, ' padding: 50px'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif'
, 'a'
, ' color #00B7FF'
].join('\n');
, ' color: #00B7FF'
].join(eol);
/**
* App template.
@@ -159,88 +173,43 @@ var app = [
, ' * Module dependencies.'
, ' */'
, ''
, 'var express = require(\'express\');'
, 'var express = require(\'express\')'
, ' , routes = require(\'./routes\')'
, ' , http = require(\'http\');'
, ''
, 'var app = module.exports = express.createServer();'
, ''
, '// Configuration'
, 'var app = express();'
, ''
, 'app.configure(function(){'
, ' app.set(\'views\', __dirname + \'/views\');'
, ' app.set(\'view engine\', \':TEMPLATE\');'
, ' app.use(express.bodyParser());'
, ' app.use(express.methodOverride());{sess}{css}'
, ' app.use(app.router);'
, ' app.use(express.favicon());'
, ' app.use(express.logger(\'dev\'));{css}'
, ' app.use(express.static(__dirname + \'/public\'));'
, ' app.use(express.bodyParser());'
, ' app.use(express.methodOverride());{sess}'
, ' app.use(app.router);'
, '});'
, ''
, 'app.configure(\'development\', function(){'
, ' app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); '
, ' app.use(express.errorHandler());'
, '});'
, ''
, 'app.configure(\'production\', function(){'
, ' app.use(express.errorHandler()); '
, '});'
, 'app.get(\'/\', routes.index);'
, ''
, '// Routes'
, 'http.createServer(app).listen(3000);'
, ''
, 'app.get(\'/\', function(req, res){'
, ' res.render(\'index\', {'
, ' title: \'Express\''
, ' });'
, '});'
, 'console.log("Express server listening on port 3000");'
, ''
, 'app.listen(3000);'
, 'console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);'
, ''
].join('\n');
// Parse arguments
var args = process.argv.slice(2)
, path = '.';
while (args.length) {
var arg = args.shift();
switch (arg) {
case '-h':
case '--help':
abort(usage);
break;
case '-v':
case '--version':
abort(version);
break;
case '-s':
case '--session':
case '--sessions':
sessions = true;
break;
case '-c':
case '--css':
args.length
? (cssEngine = args.shift())
: abort('--css requires an argument');
break;
case '-t':
case '--template':
args.length
? (templateEngine = args.shift())
: abort('--template requires an argument');
break;
default:
path = arg;
}
}
].join(eol);
// Generate application
(function createApplication(path) {
emptyDirectory(path, function(empty){
if (empty) {
if (empty || program.force) {
createApplicationAt(path);
} else {
confirm('destination is not empty, continue? ', function(ok){
program.confirm('destination is not empty, continue? ', function(ok){
if (ok) {
process.stdin.destroy();
createApplicationAt(path);
@@ -259,72 +228,100 @@ while (args.length) {
*/
function createApplicationAt(path) {
console.log();
process.on('exit', function(){
console.log();
console.log(' install dependencies:');
console.log(' $ cd %s && npm install', path);
console.log();
console.log(' run the app:');
console.log(' $ node app');
console.log();
});
mkdir(path, function(){
mkdir(path + '/public');
mkdir(path + '/public/javascripts');
mkdir(path + '/public/images');
mkdir(path + '/public/stylesheets', function(){
switch (cssEngine) {
case 'stylus':
write(path + '/public/stylesheets/style.styl', stylus);
break;
switch (program.css) {
case 'less':
write(path + '/public/stylesheets/style.less', less);
break;
case 'sass':
write(path + '/public/stylesheets/style.sass', sass);
case 'stylus':
write(path + '/public/stylesheets/style.styl', stylus);
break;
default:
write(path + '/public/stylesheets/style.css', css);
}
});
mkdir(path + '/routes', function(){
write(path + '/routes/index.js', index);
});
mkdir(path + '/views', function(){
switch (templateEngine) {
switch (program.template) {
case 'ejs':
write(path + '/views/layout.ejs', ejsLayout);
write(path + '/views/index.ejs', ejsIndex);
break;
case 'jade':
write(path + '/views/layout.jade', jadeLayout);
write(path + '/views/index.jade', jadeIndex);
break;
case 'jshtml':
write(path + '/views/layout.jshtml', jshtmlLayout);
write(path + '/views/index.jshtml', jshtmlIndex);
break;
}
});
// CSS Engine support
switch (cssEngine) {
case 'sass':
switch (program.css) {
case 'less':
app = app.replace('{css}', '\n app.use(express.compiler({ src: __dirname + \'/public\', enable: [\'' + cssEngine + '\'] }));');
app = app.replace('{css}', eol + ' app.use(require(\'less-middleware\')({ src: __dirname + \'/public\' }));');
break;
case 'stylus':
app = app.replace('{css}', '\n app.use(require(\'stylus\').middleware({ src: __dirname + \'/public\' }));');
app = app.replace('{css}', eol + ' app.use(require(\'stylus\').middleware({ src: __dirname + \'/public\' }));');
break;
default:
app = app.replace('{css}', '');
}
// Session support
app = app.replace('{sess}', sessions
? '\n app.use(express.cookieParser());\n app.use(express.session({ secret: \'your secret here\' }));'
app = app.replace('{sess}', program.sessions
? eol + ' app.use(express.cookieParser(\'your secret here\'));' + eol + ' app.use(express.session());'
: '');
// Template support
app = app.replace(':TEMPLATE', templateEngine);
app = app.replace(':TEMPLATE', program.template);
// package.json
var json = '{\n';
json += ' "name": "application-name"\n';
json += ' , "version": "0.0.1"\n';
json += ' , "private": true\n';
json += ' , "dependencies": {\n';
json += ' "express": "' + version + '"\n';
if (cssEngine) json += ' , "' + cssEngine + '": ">= 0.0.1"\n';
if (templateEngine) json += ' , "' + templateEngine + '": ">= 0.0.1"\n';
json += ' }\n';
json += '}';
var pkg = {
name: 'application-name'
, version: '0.0.1'
, private: true
, scripts: { start: 'node app' }
, dependencies: {
express: express.version
}
}
if (program.template) pkg.dependencies[program.template] = '*';
write(path + '/package.json', json);
// CSS Engine support
switch (program.css) {
case 'less':
pkg.dependencies['less-middleware'] = '*';
break;
default:
if (program.css) {
pkg.dependencies[program.css] = '*';
}
}
write(path + '/package.json', JSON.stringify(pkg, null, 2));
write(path + '/app.js', app);
});
}
@@ -355,41 +352,6 @@ function write(path, str) {
console.log(' \x1b[36mcreate\x1b[0m : ' + path);
}
/**
* Prompt confirmation with the given `msg`.
*
* @param {String} msg
* @param {Function} fn
*/
function confirm(msg, fn) {
prompt(msg, function(val){
fn(/^ *y(es)?/i.test(val));
});
}
/**
* Prompt input with the given `msg` and callback `fn`.
*
* @param {String} msg
* @param {Function} fn
*/
function prompt(msg, fn) {
// prompt
if (' ' == msg[msg.length - 1]) {
process.stdout.write(msg);
} else {
console.log(msg);
}
// stdin
process.stdin.setEncoding('ascii');
process.stdin.once('data', function(data){
fn(data);
}).resume();
}
/**
* Mkdir -p.
*
@@ -398,9 +360,9 @@ function prompt(msg, fn) {
*/
function mkdir(path, fn) {
exec('mkdir -p ' + path, function(err){
mkdirp(path, 0755, function(err){
if (err) throw err;
console.log(' \x1b[36mcreate\x1b[0m : ' + path);
console.log(' \033[36mcreate\033[0m : ' + path);
fn && fn();
});
}
+25
Ver Arquivo
@@ -0,0 +1,25 @@
var http = require('http');
var times = 50;
while (times--) {
var req = http.request({
port: 3000
, method: 'POST'
, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
req.on('response', function(res){
console.log(res.statusCode);
});
var n = 500000;
while (n--) {
req.write('foo=bar&bar=baz&');
}
req.write('foo=bar&bar=baz');
req.end();
}
+4 -4
Ver Arquivo
@@ -532,7 +532,7 @@ var app = express.createServer(
);
</code></pre>
<p>Alternatively we can <em>use()</em> them which is useful when adding middleware within <em>configure()</em> blocks, in a progressive manor.</p>
<p>Alternatively we can <em>use()</em> them which is useful when adding middleware within <em>configure()</em> blocks, in a progressive manner.</p>
<pre><code>app.use(express.logger({ format: ':method :url' }));
</code></pre>
@@ -658,7 +658,7 @@ app.get('/', all, function(){});
<h3 id="http-methods">HTTP Methods</h3>
<p>We have seen <em>app.get()</em> a few times, however Express also exposes other familiar HTTP verbs in the same manor, such as <em>app.post()</em>, <em>app.del()</em>, etc.</p>
<p>We have seen <em>app.get()</em> a few times, however Express also exposes other familiar HTTP verbs in the same manner, such as <em>app.post()</em>, <em>app.del()</em>, etc.</p>
<p> A common example for <em>POST</em> usage, is when &ldquo;submitting&rdquo; a form. Below we simply set our form method to &ldquo;post&rdquo; in our html, and control will be given to the route we have defined below it.</p>
@@ -1451,7 +1451,7 @@ partial('movie', movie)
<pre><code> res.local('foo', bar);
res.local('bar', baz);
res.locals({ foo: bar, bar, baz });
res.locals({ foo: bar, bar: baz });
</code></pre>
<h3 id="app.set()">app.set(name[, val])</h3>
@@ -1804,4 +1804,4 @@ Hello World
</div>
</div>
</body>
</html>
</html>
+60 -118
Ver Arquivo
@@ -107,8 +107,8 @@ Express supports the following settings out of the box:
* _home_ Application base path used for _res.redirect()_ and transparently handling mounted apps.
* _views_ Root views directory defaulting to **CWD/views**
* _view engine_ Default view engine name for views rendered without extensions
* _view options_ An object specifying global view options
* _view cache_ Enable view caching (enabled in production)
* _charset_ Alter the default charset of "utf-8"
* _case sensitive routes_ Enable case-sensitive routing
* _strict routing_ When enabled trailing slashes are no longer ignored
* _jsonp callback_ Enable _res.send()_ / _res.json()_ transparent jsonp support
@@ -245,7 +245,7 @@ The _app.all()_ method is useful for applying the same logic for all HTTP verbs
});
app.get('*', function(req, res){
res.send('what???', 404);
res.send(404, 'what???');
});
app.listen(3000);
@@ -262,7 +262,7 @@ passed to _express.createServer()_ as you would with a regular Connect server. F
, express.bodyParser()
);
Alternatively we can _use()_ them which is useful when adding middleware within _configure()_ blocks, in a progressive manor.
Alternatively we can _use()_ them which is useful when adding middleware within _configure()_ blocks, in a progressive manner.
app.use(express.logger({ format: ':method :url' }));
@@ -379,7 +379,7 @@ There are times when we may want to "skip" passed remaining route middleware, bu
### HTTP Methods
We have seen _app.get()_ a few times, however Express also exposes other familiar HTTP verbs in the same manor, such as _app.post()_, _app.del()_, etc.
We have seen _app.get()_ a few times, however Express also exposes other familiar HTTP verbs in the same manner, such as _app.post()_, _app.del()_, etc.
A common example for _POST_ usage, is when "submitting" a form. Below we simply set our form method to "post" in our html, and control will be given to the route we have defined below it.
@@ -421,65 +421,16 @@ The reason that these are not always defaults, is simply because these are not r
### Error Handling
Express provides the _app.error()_ method which receives exceptions thrown within a route,
or passed to _next(err)_. Below is an example which serves different pages based on our
ad-hoc _NotFound_ exception:
function NotFound(msg){
this.name = 'NotFound';
Error.call(this, msg);
Error.captureStackTrace(this, arguments.callee);
}
NotFound.prototype.__proto__ = Error.prototype;
app.get('/404', function(req, res){
throw new NotFound;
Error handling middleware are simply middleware with an arity of 4, aka
the signature _(err, req, res, next)_. When you _next(err)_ an error,
only these middleware are executed and have a chance to respond. For example:
app.use(app.bodyParser());
app.use(app.methodOverride());
app.use(app.router);
app.use(function(err, req, res, next){
res.send(500, 'Server error');
});
app.get('/500', function(req, res){
throw new Error('keyboard cat!');
});
We can call _app.error()_ several times as shown below.
Here we check for an instanceof _NotFound_ and show the
404 page, or we pass on to the next error handler.
Note that these handlers can be defined anywhere, as they
will be placed below the route handlers on _listen()_. This
allows for definition within _configure()_ blocks so we can
handle exceptions in different ways based on the environment.
app.error(function(err, req, res, next){
if (err instanceof NotFound) {
res.render('404.jade');
} else {
next(err);
}
});
Here we assume all errors as 500 for the simplicity of
this demo, however you can choose whatever you like. For example when node performs filesystem syscalls, you may receive an error object with the _error.code_ of _ENOENT_, meaning "no such file or directory", we can utilize this in our error handling and display a page specific to this if desired.
app.error(function(err, req, res){
res.render('500.jade', {
error: err
});
});
Our apps could also utilize the Connect _errorHandler_ middleware
to report on exceptions. For example if we wish to output exceptions
in "development" mode to _stderr_ we can use:
app.use(express.errorHandler({ dumpExceptions: true }));
Also during development we may want fancy html pages to show exceptions
that are passed or thrown, so we can set _showStack_ to true:
app.use(express.errorHandler({ showStack: true, dumpExceptions: true }));
The _errorHandler_ middleware also responds with _json_ if _Accept: application/json_
is present, which is useful for developing apps that rely heavily on client-side JavaScript.
### Route Param Pre-conditions
@@ -542,13 +493,11 @@ mix and match template engines:
res.render('another-page.ejs');
Express also provides the _view options_ setting, which is applied each time a view is rendered, so for example if you rarely use layouts you may set:
To apply application-level locals, or view engine options may be set using _app.local()_ or _app.locals()_, for example if we don't want layouts for most of our templates we may do:
app.set('view options', {
layout: false
});
app.local('layout', false);
Which can then be overridden within the _res.render()_ call if need be:
Which can then be overridden within the _res.render()_ call if desired, and is otherwise functionally equivalent to passing directly to `res.render()`:
res.render('myview.ejs', { layout: true });
@@ -564,13 +513,6 @@ These paths may also be absolute:
res.render('page', { layout: __dirname + '/../../mylayout.jade' });
A good example of this is specifying custom _ejs_ opening and closing tags:
app.set('view options', {
open: '{{',
close: '}}'
});
### View Partials
The Express view system has built-in support for partials and collections, which are "mini" views representing a document fragment. For example rather than iterating
@@ -647,7 +589,7 @@ Now the _req.session_ and _req.sessionStore_ properties will be accessible to al
// we could check req.session.items && req.session.items.length
// to print out a message
if (req.session.items && req.session.items.length) {
req.flash('info', 'You have %s items in your cart', req.session.items.length);
req.notify('info', 'You have %s items in your cart', req.session.items.length);
}
res.render('shopping-cart');
});
@@ -772,27 +714,29 @@ the _express.bodyParser middleware.
req.get('Content-Type', 'boundary');
// => "--foo-bar-baz"
### req.flash(type[, msg])
### req.notify(type[, msg])
Queue flash _msg_ of the given _type_.
req.flash('info', 'email sent');
req.flash('error', 'email delivery failed');
req.flash('info', 'email re-sent');
req.notify('info', 'email sent');
req.notify('error', 'email delivery failed');
req.notify('info', 'email re-sent');
// => 2
req.flash('info');
req.notify('info');
// => ['email sent', 'email re-sent']
req.flash('info');
req.notify('info');
// => []
req.flash();
req.notify();
// => { error: ['email delivery failed'], info: [] }
Flash notification message may also utilize formatters, by default only the %s string formatter is available:
Flash notification message may also utilize formatters, by default only the %s string and %d integer formatters is available:
req.flash('info', 'email delivery to _%s_ from _%s_ failed.', toUser, fromUser);
req.notify('info', 'email delivery to <em>%s</em> from <em>%s</em> failed.', toUser, fromUser);
Argument HTML is escaped, to prevent XSS, however HTML notification format is valid.
### req.isXMLHttpRequest
@@ -855,6 +799,21 @@ Sets the _Content-Disposition_ response header to "attachment", with optional _f
res.attachment('path/to/my/image.png');
### res.status(code)
Sets the `res.statusCode` property to `code` and returns for chaining:
res.status(500).send('Something bad happened');
is equivalent to:
res.statusCode = 500;
res.send('Something bad happened');
and:
res.send(500, 'Something bad happened');
### res.sendfile(path[, options[, callback]])
Used by `res.download()` to transfer an arbitrary file.
@@ -904,36 +863,31 @@ An optional second callback, _callback2_ may be given to allow you to act on con
// connection related error
});
### res.send(body|status[, headers|status[, status]])
### res.send(body|status[, body])
The _res.send()_ method is a high level response utility allowing you to pass
objects to respond with json, strings for html, Buffer instances, or numbers representing the status code. The following are all valid uses:
res.send(); // 204
res.send(new Buffer('wahoo'));
res.send({ some: 'json' });
res.send(201, { message: 'User created' });
res.send('<p>some html</p>');
res.send('Sorry, cant find that', 404);
res.send('text', { 'Content-Type': 'text/plain' }, 201);
res.send(404);
res.send(404, 'Sorry, cant find that');
res.send(404); // "Not Found"
res.send(500); // "Internal Server Error"
By default the _Content-Type_ response header is set, however if explicitly
assigned through `res.send()` or previously with `res.header()` or `res.contentType()`
it will not be set again.
The _Content-Type_ response header is defaulted appropriately unless previously defined via `res.header()` / `res.contentType()` etc.
Note that this method _end()_s the response, so you will want to use node's _res.write()_ for multiple writes or streaming.
### res.json(obj[, headers|status[, status]])
### res.json(obj|status[, obj])
Send a JSON response with optional _headers_ and _status_. This method
is ideal for JSON-only APIs, however _res.send(obj)_ will send JSON as
well, though not ideal for cases when you want to send for example a string
as JSON, since the default for _res.send(string)_ is text/html.
Send an explicit JSON response. This method is ideal for JSON-only APIs, while it is much like _res.send(obj)_, send is not ideal for cases when you want to send for example a single string as JSON, since the default for _res.send(string)_ is text/html.
res.json(null);
res.json({ user: 'tj' });
res.json('oh noes!', 500);
res.json('I dont have that', 404);
res.json(500, 'oh noes!');
res.json(404, 'I dont have that');
### res.redirect(url[, status])
@@ -1209,21 +1163,11 @@ When mounted, _res.redirect()_ will respect the mount-point. For example if a bl
res.redirect('/posts');
### app.error(function)
### app.locals(obj)
Adds an error handler _function_ which will receive the exception as the first parameter as shown below.
Note that we may set several error handlers by making several calls to this method, however the handler
should call _next(err)_ if it does not wish to deal with the exception:
Registers static view locals.
app.error(function(err, req, res, next){
res.send(err.message, 500);
});
### app.helpers(obj)
Registers static view helpers.
app.helpers({
app.locals({
name: function(first, last){ return first + ', ' + last }
, firstName: 'tj'
, lastName: 'holowaychuk'
@@ -1239,16 +1183,14 @@ Express also provides a few locals by default:
- `settings` the app's settings object
- `layout(path)` specify the layout from within a view
This method is aliased as _app.locals()_.
### app.dynamicLocals(obj)
### app.dynamicHelpers(obj)
Registers dynamic view helpers. Dynamic view helpers
Registers dynamic view locals. Dynamic locals
are simply functions which accept _req_, _res_, and are
evaluated against the _Server_ instance before a view is rendered. The _return value_ of this function
evaluated against the _Server_ instance before a view is rendered, and are unique to that specific request. The _return value_ of this function
becomes the local variable it is associated with.
app.dynamicHelpers({
app.dynamicLocals({
session: function(req, res){
return req.session;
}
+1
Ver Arquivo
@@ -51,3 +51,4 @@ The following modules compliment or extend Express directly:
* [Google Group](http://groups.google.com/group/express-js) for discussion
* Visit the [Wiki](http://github.com/visionmedia/express/wiki)
* [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito)
* [Русскоязычная документация](http://express-js.ru/)
+33 -34
Ver Arquivo
@@ -6,47 +6,49 @@
var express = require('../../lib/express')
, crypto = require('crypto');
var app = express.createServer(
express.bodyParser()
, express.cookieParser()
, express.session({ secret: 'keyboard cat' })
);
var app = module.exports = express();
app.use(express.bodyParser());
app.use(express.cookieParser('shhhh, very secret'));
app.use(express.session());
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
// Message helper, ideally we would use req.flash()
// however this is more light-weight for an example
// Session-persisted message middleware
app.dynamicHelpers({
message: function(req){
var err = req.session.error
, msg = req.session.success;
delete req.session.error;
delete req.session.success;
if (err) return '<p class="msg error">' + err + '</p>';
if (msg) return '<p class="msg success">' + msg + '</p>';
}
});
app.locals.use(function(req,res){
var err = req.session.error
, msg = req.session.success;
delete req.session.error;
delete req.session.success;
res.locals.message = '';
if (err) res.locals.message = '<p class="msg error">' + err + '</p>';
if (msg) res.locals.message = '<p class="msg success">' + msg + '</p>';
})
// Generate a salt for the user to prevent rainbow table attacks
// for better security take a look at the bcrypt c++ addon:
// https://github.com/ncb000gt/node.bcrypt.js
var users = {
tj: {
name: 'tj'
name: 'tj'
, salt: 'randomly-generated-salt'
, pass: hash('foobar', 'randomly-generated-salt')
}
};
// Used to generate a hash of the plain-text password + salt
function hash(msg, key) {
return crypto.createHmac('sha256', key).update(msg).digest('hex');
return crypto
.createHmac('sha256', key)
.update(msg)
.digest('hex');
}
// Authenticate using our plain-object database of doom!
// Authenticate using our plain-object database of doom!
function authenticate(name, pass, fn) {
console.log('authenticating %s:%s', name, pass);
var user = users[name];
// query the db for the given username
if (!user) return fn(new Error('cannot find user'));
@@ -67,16 +69,11 @@ function restrict(req, res, next) {
}
}
function accessLogger(req, res, next) {
console.log('/restricted accessed by %s', req.session.user.name);
next();
}
app.get('/', function(req, res){
res.redirect('/login');
res.redirect('login');
});
app.get('/restricted', restrict, accessLogger, function(req, res){
app.get('/restricted', restrict, function(req, res){
res.send('Wahoo! restricted area');
});
@@ -84,7 +81,7 @@ app.get('/logout', function(req, res){
// destroy the user's session to log them out
// will be re-created next request
req.session.destroy(function(){
res.redirect('home');
res.redirect('/');
});
});
@@ -113,10 +110,12 @@ app.post('/login', function(req, res){
req.session.error = 'Authentication failed, please check your '
+ ' username and password.'
+ ' (use "tj" and "foobar")';
res.redirect('back');
res.redirect('login');
}
});
});
app.listen(3000);
console.log('Express started on port 3000');
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
<h1>Login</h1>
<%- message %>
Try accessing <a href="/restricted">/restricted</a>.
Try accessing <a href="/restricted">/restricted</a>, then authenticate with "tj" and "foobar".
<form method="post" action="/login">
<p>
<label>Username:</label>
-58
Ver Arquivo
@@ -1,58 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../../lib/express')
, messages = require('express-messages');
var app = module.exports = express.createServer();
// Config
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
// mount hook
app.mounted(function(other){
console.log('ive been mounted!');
});
// Flash message helper provided by express-messages
// $ npm install express-messages
app.dynamicHelpers({
messages: messages
, base: function(){
// return the app's mount-point
// so that urls can adjust. For example
// if you run this example /post/add works
// however if you run the mounting example
// it adjusts to /blog/post/add
return '/' == app.route ? '' : app.route;
}
});
// Middleware
app.configure(function(){
app.use(express.logger('\x1b[33m:method\x1b[0m \x1b[32m:url\x1b[0m :response-time'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.session({ secret: 'keyboard cat' }));
app.use(app.router);
app.use(express.static(__dirname + '/public'));
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
// Routes
require('./routes/site')(app);
require('./routes/post')(app);
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
+50
Ver Arquivo
@@ -0,0 +1,50 @@
/**
* Module dependencies.
*/
var express = require('../../')
, app = module.exports = express();
// config
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
// middleware
app.configure('development',function(){
app.use(express.logger('dev'));
})
app.configure(function(){
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('keyboard cat'));
app.use(express.session());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
// Locals
app.locals.use(function(req, res){
// expose "error" and "message" to all
// views that are rendered.
res.locals.error = req.session.error || '';
res.locals.message = req.session.message || '';
// remove them so they're not displayed on subsequent renders
delete req.session.error;
delete req.session.message;
});
// Routes
require('./routes/site')(app);
require('./routes/post')(app);
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
+3 -3
Ver Arquivo
@@ -17,11 +17,11 @@ Post.prototype.save = function(fn){
};
Post.prototype.validate = function(fn){
if (!this.title) return fn(new Error('_title_ required'));
if (!this.body) return fn(new Error('_body_ required'));
if (!this.title) return fn(new Error('title required'));
if (!this.body) return fn(new Error('body required'));
if (this.body.length < 10) {
return fn(new Error(
'_body_ should be at least **10** characters long, was only _' + this.title.length + '_'));
'body should be at least 10 characters long, was only ' + this.title.length));
}
fn();
};
+6 -8
Ver Arquivo
@@ -41,18 +41,16 @@ a.edit {
.date {
font-size: 11px;
}
#messages ul {
p.error,
p.message {
padding: 10px;
border: 1px solid;
}
#messages ul li {
list-style: none;
p.error {
background: #FDEAE7;
color: #E4250C;
}
#messages ul.info {
p.message {
color: #2EBBE6;
background: #F7FBFD;
}
#messages ul.error {
color: #E4250C;
background: #FDEAE7;
}
+7 -6
Ver Arquivo
@@ -42,17 +42,17 @@ module.exports = function(app){
*/
app.post('/post', function(req, res){
var data = req.body.post
var data = req.body.post || {}
, post = new Post(data.title, data.body);
post.validate(function(err){
if (err) {
req.flash('error', err.message);
req.session.error = err.message;
return res.redirect('back');
}
post.save(function(err){
req.flash('info', 'Successfully created post _%s_', post.title);
req.session.message = 'Successfully created the post.';
res.redirect('/post/' + post.id);
});
});
@@ -82,12 +82,13 @@ module.exports = function(app){
var post = req.post;
post.validate(function(err){
if (err) {
req.flash('error', err.message);
req.session.error = err.message;
return res.redirect('back');
}
post.update(req.body.post, function(err){
if (err) return next(err);
req.flash('info', 'Successfully updated post');
req.session.message = 'Successfully updated post';
res.redirect('back');
});
});
+20 -17
Ver Arquivo
@@ -1,19 +1,22 @@
h1 Blog
extends layout
!= messages()
block content
h1 Blog
- if (count)
p Display all #{count} post(s)
#posts!= partial('post', posts)
- else
p
| It looks like you have no posts!
p
| Click
a(href=base + '/post/add') here
| to create a post. Login
| as
em "admin"
| and
em "express"
| .
if count
p Display all #{count} post(s)
#posts
each post in posts
include post/index
else
p
| It looks like you have no posts!
p
| Click
a(href='/post/add') here
| to create a post. Login
| as
em "admin"
| and
em "express"
| .
+3 -2
Ver Arquivo
@@ -2,6 +2,7 @@
html
head
title Blog
link(rel='stylesheet', href=base + '/style.css')
link(rel='stylesheet', href='/style.css')
body
#container!= body
#container
block content
+6
Ver Arquivo
@@ -0,0 +1,6 @@
if error
p.error= error
if message
p.message= message
+19 -17
Ver Arquivo
@@ -1,20 +1,22 @@
extends ../layout
- if (post.title)
h1 Editing #{post.title}
- else
h1 New Post
block content
if post.title
h1 Editing #{post.title}
else
h1 New Post
!= messages()
include ../messages
form#post(action=base + '/post' + (post.title ? '/' + post.id : ''), method='post')
- if (post.title)
input(type='hidden', name='_method', value='put')
p
label(for='post[title]') Title:
input(type='text', name='post[title]', value=post.title)
p
label(for='post[body]') Body:
textarea(name='post[body]')= post.body || ''
p
input(type='submit', value=post.title ? 'Update' : 'Create')
form#post(action='/post' + (post.title ? '/' + post.id : ''), method='post')
if post.title
input(type='hidden', name='_method', value='put')
p
label(for='post[title]') Title:
input(type='text', name='post[title]', value=post.title)
p
label(for='post[body]') Body:
textarea(name='post[body]')= post.body || ''
p
input(type='submit', value=post.title ? 'Update' : 'Create')
+18 -16
Ver Arquivo
@@ -1,16 +1,18 @@
.post
// title
h2
= post.title
a.edit(href=base + '/post/' + post.id + '/edit') Edit
// flash messages
!= messages()
// dates
p.date.created Created at #{post.createdAt}
- if (post.updatedAt)
p.date.updated Updated at #{post.updatedAt}
// body
pre.body= post.body
extends ../layout
block content
.post
// title
h2
= post.title
a.edit(href='/post/' + post.id + '/edit') Edit
include ../messages
// dates
p.date.created Created at #{post.createdAt}
if post.updatedAt
p.date.updated Updated at #{post.updatedAt}
// body
pre.body= post.body
-47
Ver Arquivo
@@ -1,47 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../../lib/express');
var app = express.createServer();
var users = [
{ name: 'tobi' }
, { name: 'loki' }
, { name: 'jane' }
];
function provides(type) {
return function(req, res, next){
if (req.accepts(type)) return next();
next('route');
}
}
// curl http://localhost:3000/users -H "Accept: application/json"
app.get('/users', provides('json'), function(req, res){
res.send(users);
});
// curl http://localhost:3000/users -H "Accept: text/html"
app.get('/users', provides('html'), function(req, res){
res.send('<ul>' + users.map(function(user){
return '<li>' + user.name + '</li>';
}).join('\n') + '</ul>');
});
// curl http://localhost:3000/users -H "Accept: text/plain"
app.get('/users', function(req, res, next){
res.contentType('txt');
res.send(users.map(function(user){
return user.name;
}).join(', '));
});
app.listen(3000);
console.log('Express server listening on port 3000');
+34
Ver Arquivo
@@ -0,0 +1,34 @@
var express = require('../../')
, app = module.exports = express();
var users = [];
users.push({ name: 'Tobi' });
users.push({ name: 'Loki' });
users.push({ name: 'Jane' });
app.get('/', function(req, res){
res.format({
html: function(){
res.send('<ul>' + users.map(function(user){
return '<li>' + user.name + '</li>';
}).join('') + '</ul>');
},
text: function(){
res.send(users.map(function(user){
return ' - ' + user.name + '\n';
}).join(''));
},
json: function(){
res.json(users);
}
})
});
if (!module.parent) {
app.listen(3000);
console.log('listening on port 3000');
}
+29
Ver Arquivo
@@ -0,0 +1,29 @@
/**
* Module dependencies.
*/
var express = require('../../');
var app = module.exports = express();
// pass a secret to cookieParser() for signed cookies
app.use(express.cookieParser('manny is cool'));
// add req.session cookie support
app.use(express.cookieSessions());
// do something with the session
app.use(count);
// custom middleware
function count(req, res) {
req.session.count = req.session.count || 0;
var n = req.session.count++;
res.send('viewed ' + n + ' times\n');
}
if (!module.parent) {
app.listen(3000);
console.log('Express server listening on port 3000');
}
+23 -14
Ver Arquivo
@@ -3,22 +3,29 @@
* Module dependencies.
*/
var express = require('../../lib/express');
var express = require('../../')
, app = module.exports = express();
var app = express.createServer(
// Place default Connect favicon above logger so it is not in
// the logging output
express.favicon(),
// Custom logger format
express.logger({ format: '\x1b[36m:method\x1b[0m \x1b[90m:url\x1b[0m :response-time' }),
// add favicon() before logger() so
// GET /favicon.ico requests are not
// logged, because this middleware
// reponds to /favicon.ico and does not
// call next()
app.use(express.favicon());
// Provides req.cookies
express.cookieParser(),
// custom log format
if ('test' != process.env.NODE_ENV)
app.use(express.logger(':method :url'));
// Parses x-www-form-urlencoded request bodies (and json)
express.bodyParser()
);
// parses request cookies, populating
// req.cookies and req.signedCookies
// when the secret is passed, used
// for signing the cookies.
app.use(express.cookieParser('my secret here'));
// parses json, x-www-form-urlencoded, and multipart/form-data
app.use(express.bodyParser());
app.get('/', function(req, res){
if (req.cookies.remember) {
@@ -41,5 +48,7 @@ app.post('/', function(req, res){
res.redirect('back');
});
app.listen(3000);
console.log('Express started on port 3000');
if (!module.parent){
app.listen(3000);
console.log('Express started on port 3000');
}
+17 -24
Ver Arquivo
@@ -3,9 +3,8 @@
* Module dependencies.
*/
var express = require('../../lib/express');
var app = express.createServer();
var express = require('../../')
, app = module.exports = express();
app.get('/', function(req, res){
res.send('<ul>'
@@ -19,33 +18,27 @@ app.get('/', function(req, res){
app.get('/files/:file(*)', function(req, res, next){
var file = req.params.file
, path = __dirname + '/files/' + file;
// either res.download(path) and let
// express handle failures, or provide
// a callback as shown below
res.download(path, function(err){
// if an error occurs in this callback
// the file most likely does not exist,
// and it's safe to respond or next(err)
if (err) return next(err);
// the file has been transferred, do not respond
// from here, though you may use this callback
// for stats etc.
console.log('transferred %s', path);
}, function(err){
// this second optional callback is used when
// an error occurs during transmission
});
res.download(path);
});
app.error(function(err, req, res, next){
if ('ENOENT' == err.code) {
// error handling middleware. Because it's
// below our routes, you will be able to
// "intercept" errors, otherwise Connect
// will respond with 500 "Internal Server Error".
app.use(function(err, req, res, next){
// special-case 404s,
// remember you could
// render a 404 template here
if (404 == err.status) {
res.statusCode = 404;
res.send('Cant find that file, sorry!');
} else {
// Not a 404
next(err);
}
});
app.listen(3000);
console.log('Express started on port 3000');
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
-31
Ver Arquivo
@@ -1,31 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../../lib/express');
var app = express.createServer();
// Register ejs as .html
app.register('.html', require('ejs'));
// Optional since express defaults to CWD/views
app.set('views', __dirname + '/views');
app.set('view engine', 'html');
// Dummy users
var users = [
{ name: 'tj', email: 'tj@sencha.com' }
, { name: 'ciaran', email: 'ciaranj@gmail.com' }
, { name: 'aaron', email: 'aaron.heckmann+github@gmail.com' }
];
app.get('/', function(req, res){
res.render('users', { users: users });
});
app.listen(3000);
console.log('Express app started on port 3000');
+46
Ver Arquivo
@@ -0,0 +1,46 @@
/**
* Module dependencies.
*/
var express = require('../../');
var app = module.exports = express();
// Register ejs as .html. If we did
// not call this, we would need to
// name our views foo.ejs instead
// of foo.html. The __express method
// is simply a function that engines
// use to hook into the Express view
// system by default, so if we want
// to change "foo.ejs" to "foo.html"
// we simply pass _any_ function, in this
// case `ejs.__express`.
app.engine('.html', require('ejs').__express);
// Optional since express defaults to CWD/views
app.set('views', __dirname + '/views');
// Without this you would need to
// supply the extension to res.render()
// ex: res.render('users.html').
app.set('view engine', 'html');
// Dummy users
var users = [
{ name: 'tobi', email: 'tobi@learnboost.com' }
, { name: 'loki', email: 'loki@learnboost.com' }
, { name: 'jane', email: 'jane@learnboost.com' }
];
app.get('/', function(req, res){
res.render('users', { users: users });
});
if (!module.parent) {
app.listen(3000);
console.log('Express app started on port 3000');
}
-6
Ver Arquivo
@@ -1,6 +0,0 @@
<html>
<body>
<h1>Users</h1>
<%- body %>
</body>
</html>
+6
Ver Arquivo
@@ -0,0 +1,6 @@
<h1>Users</h1>
<ul id="users">
<% users.forEach(function(user){ %>
<li><%= user.name %> <%= user.email %></li>
<% }) %>
</ul>
-3
Ver Arquivo
@@ -1,3 +0,0 @@
<ul id="users">
<%- partial('user', users) %>
</ul>
-1
Ver Arquivo
@@ -1 +0,0 @@
<li><%= user.name %> &lt;<%= user.email %>&gt;</li>
+34 -22
Ver Arquivo
@@ -1,27 +1,25 @@
// Expose modules in ./support for demo purposes
require.paths.unshift(__dirname + '/../../support');
/**
* Module dependencies.
*/
var express = require('../../lib/express');
var express = require('../../')
, app = module.exports = express()
, silent = 'test' == process.env.NODE_ENV;
var app = express.createServer();
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
// Serve default connect favicon
app.use(express.favicon());
// Logger is placed below favicon, so favicon.ico
// requests will not be logged
app.use(express.logger('":method :url" :status'));
silent || app.use(express.logger('dev'));
// "app.router" positions our routes
// specifically above the middleware
// assigned below
// above the middleware defined below,
// this means that Express will attempt
// to match & call routes _before_ continuing
// on, at which point we assume it's a 404 because
// no route has handled the request.
app.use(app.router);
@@ -29,11 +27,26 @@ app.use(app.router);
// middleware use()d, we assume 404, as nothing else
// responded.
// $ curl http://localhost:3000/notfound
// $ curl http://localhost:3000/notfound -H "Accept: application/json"
// $ curl http://localhost:3000/notfound -H "Accept: text/plain"
app.use(function(req, res, next){
// the status option, or res.statusCode = 404
// are equivalent, however with the option we
// get the "status" local available as well
res.render('404', { status: 404, url: req.url });
// respond with html page
if (req.accepts('html')) {
res.status(404);
res.render('404', { url: req.url });
return;
}
// respond with json
if (req.accepts('json')) {
res.send({ error: 'Not found' });
return;
}
// default to plain-text. send()
res.type('txt').send('Not found');
});
// error-handling middleware, take the same form
@@ -48,15 +61,12 @@ app.use(function(req, res, next){
// would remain being executed, however here
// we simply respond with an error page.
app.use(function(err, req, res, next){
// we may use properties of the error object
// here and next(err) appropriately, or if
// we possibly recovered from the error, simply next().
res.render('500', {
status: err.status || 500
, error: err
});
res.status(err.status || 500);
res.render('500', { error: err });
});
// Routes
@@ -79,5 +89,7 @@ app.get('/500', function(req, res, next){
next(new Error('keyboard cat!'));
});
app.listen(3000);
console.log('Express app started on port 3000');
if (!module.parent) {
app.listen(3000);
silent || console.log('Express started on port 3000');
}
+5 -1
Ver Arquivo
@@ -1 +1,5 @@
h2 Cannot find #{url}
extends error
block content
h2 Cannot find #{url}
+10 -2
Ver Arquivo
@@ -1,2 +1,10 @@
h1 Error: #{error.message}
pre= error.stack
// note that we extend a different
// layout with jade for 4xx & 5xx
// responses
extends error
block content
h1 Error: #{error.message}
pre= error.stack
+6
Ver Arquivo
@@ -0,0 +1,6 @@
html
head
title Error
body
h1 An error occurred!
block content
+15 -11
Ver Arquivo
@@ -1,11 +1,15 @@
h2 Pages Example
ul
li
| visit
a(href="/500") 500
li
| visit
a(href="/404") 404
li
| visit
a(href='/403') 403
extends layout
block content
h2 Pages Example
ul
li
| visit
a(href="/500") 500
li
| visit
a(href="/404") 404
li
| visit
a(href='/403') 403
+1 -1
Ver Arquivo
@@ -3,4 +3,4 @@ html
title Custom Pages Example
body
h1 My Site
!= body
block content
+33 -10
Ver Arquivo
@@ -3,9 +3,33 @@
* Module dependencies.
*/
var express = require('../../lib/express');
var express = require('../../')
, app = module.exports = express();
var app = express.createServer();
if ('test' != process.env.NODE_ENV)
app.use(express.logger('dev'));
app.use(app.router);
// the error handler is strategically
// placed *below* the app.router; if it
// were above it would not receive errors
// from app.get() etc
app.use(error);
// error handling middleware have an arity of 4
// instead of the typical (req, res, next),
// otherwise they behave exactly like regular
// middleware, you may have several of them,
// in different orders etc.
function error(err, req, res, next) {
// log it
if ('test' != process.env.NODE_ENV)
console.error(err.stack);
// respond with 500 "Internal Server Error".
res.send(500);
}
app.get('/', function(req, res){
// Caught and passed down to the errorHandler middleware
@@ -14,13 +38,12 @@ app.get('/', function(req, res){
app.get('/next', function(req, res, next){
// We can also pass exceptions to next()
next(new Error('oh no!'))
process.nextTick(function(){
next(new Error('oh no!'));
});
});
// The errorHandler middleware in this case will dump exceptions to stderr
// as well as show the stack trace in responses, currently handles text/plain,
// text/html, and application/json responses to aid in development
app.use('/', express.errorHandler({ dump: true, stack: true }));
app.listen(3000);
console.log('app listening on port 3000');
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
-66
Ver Arquivo
@@ -1,66 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../../lib/express');
var app = express.createServer();
// Register ejs as .html
app.register('.html', require('ejs'));
// Optional since express defaults to CWD/views
app.set('views', __dirname + '/views');
app.set('view engine', 'html');
// Dummy users
var users = [
{ name: 'tj', email: 'tj@sencha.com' }
, { name: 'ciaran', email: 'ciaranj@gmail.com' }
, { name: 'aaron', email: 'aaron.heckmann+github@gmail.com' }
];
// dynamic helpers are simply functions that are invoked
// per request (once), passed both the request and response
// objects. These can be used for request-specific
// details within a view, such telling the layout which
// scripts to include.
app.dynamicHelpers({
// by simply returning an object here
// we can set it's properties such as "page.title"
// within a view, and it remains specific to that request,
// so it would be valid to do:
// page.title = user.name + "'s account"
page: function() {
return {};
},
// the scripts array here is assigned once,
// so by returning a closure, we can use script(path)
// in a template, instead of something like
// scripts.push(path).
script: function(req){
req._scripts = [];
return function(path){
req._scripts.push(path);
}
},
// to expose our scripts array for iteration within
// our views (typically the layout), we simply return it
// here, and since composite types are mutable, it will
// contain all of the paths pushed with the helper above.
scripts: function(req){
return req._scripts;
}
});
app.get('/', function(req, res){
res.render('users', { users: users });
});
app.listen(3000);
console.log('Express app started on port 3000');
@@ -1,11 +0,0 @@
<html>
<head>
<title><%- page.title %></title>
<% for (var i in scripts) { %>
<script src="<%= scripts[i] %>"></script>
<% } %>
</head>
<body>
<%- body %>
</body>
</html>
@@ -1,8 +0,0 @@
<% page.title = 'Users' %>
<% script('/javascripts/jquery.js') %>
<% script('/javascripts/users.js') %>
<h1>Users</h1>
<ul id="users">
<%- partial('user', users) %>
</ul>
@@ -1 +0,0 @@
<li><%= user.name %> &lt;<%= user.email %>&gt;</li>
-46
Ver Arquivo
@@ -1,46 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../../lib/express');
// App with session support
var app = express.createServer(
express.cookieParser()
, express.session({ secret: 'keyboard cat' })
);
// View settings
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.dynamicHelpers({
// express-messages is a dynamicHelper that
// renders the flash messages to HTML for you
// $ npm install express-messages
messages: require('express-messages')
});
app.dynamicHelpers({
// Another dynamic helper example. Since dynamic
// helpers resolve at view rendering time, we can
// "inject" the "page" local variable per request
// providing us with the request url.
page: function(req, res){
return req.url;
}
});
app.get('/', function(req, res){
// Not very realistic notifications but illustrates usage
req.flash('info', 'email queued');
req.flash('info', 'email sent');
req.flash('error', 'delivery failed');
res.render('index');
});
app.listen(3000);
console.log('Express app started on port 3000');
-3
Ver Arquivo
@@ -1,3 +0,0 @@
<h1>Flash Message Example</h1>
<p>on page <%- page %></p>
<%- messages() %>
-5
Ver Arquivo
@@ -1,5 +0,0 @@
<html>
<body>
<%- body %>
</body>
</html>
+6 -8
Ver Arquivo
@@ -1,14 +1,10 @@
// Expose modules in ./support for demo purposes
require.paths.unshift(__dirname + '/../../support');
/**
* Module dependencies.
*/
var express = require('../../lib/express');
var express = require('../../');
var app = express.createServer();
var app = module.exports = express();
// Here we use the bodyDecoder middleware
// to parse urlencoded request bodies
@@ -77,5 +73,7 @@ app.put('/', function(req, res){
res.redirect('/?name=' + req.body.name);
});
app.listen(3000);
console.log('Express app started on port 3000');
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
+8 -7
Ver Arquivo
@@ -3,9 +3,9 @@
* Module dependencies.
*/
var express = require('../../lib/express');
var express = require('../../');
var app = express.createServer();
var app = module.exports = express();
// Fake items
@@ -45,8 +45,7 @@ app.get('/item/:id.:format?', function(req, res, next){
+ '<items>'
+ '<item>' + item.name + '</item>'
+ '</items>';
res.contentType('.xml');
res.send(xml);
res.type('xml').send(xml);
break;
case 'html':
default:
@@ -62,7 +61,9 @@ app.get('/item/:id.:format?', function(req, res, next){
// Middleware
app.use(express.errorHandler({ showStack: true }));
app.use(express.errorHandler());
app.listen(3000);
console.log('Express app started on port 3000');
if (!module.parent) {
app.listen(3000);
silent || console.log('Express started on port 3000');
}
+1 -1
Ver Arquivo
@@ -6,7 +6,7 @@
var express = require('../../lib/express')
, http = require('http');
var app = express.createServer();
var app = express();
// Expose our views
+14 -8
Ver Arquivo
@@ -1,8 +1,14 @@
- each user in users
.user
h2= user.name
p.summary
| <a href="http://github.com/#{user.name}">#{user.name}</a> has
| <strong>#{user.repos.length}</strong> repositories
| with a total of <strong>#{user.totalWatchers}</strong> watchers.
table#repos!= partial('repo', user.repos)
extends layout
block content
each user in users
.user
h2= user.name
p.summary
| <a href="http://github.com/#{user.name}">#{user.name}</a> has
| <strong>#{user.repos.length}</strong> repositories
| with a total of <strong>#{user.totalWatchers}</strong> watchers.
table#repos
for repo in user.repos
include repo
+2 -1
Ver Arquivo
@@ -4,4 +4,5 @@ html
title Github Example
link(rel="stylesheet", href="/style.css")
body
#container!= body
#container
block content
+3 -2
Ver Arquivo
@@ -3,12 +3,13 @@
* Module dependencies.
*/
var express = require('../../lib/express');
var express = require('../../');
var app = express.createServer();
var app = express();
app.get('/', function(req, res){
res.send('Hello World');
});
app.listen(3000);
console.log('Express started on port 3000');
+3
Ver Arquivo
@@ -0,0 +1,3 @@
head
title Jade Example
link(rel="stylesheet", href="/stylesheets/style.css")
+1 -3
Ver Arquivo
@@ -1,6 +1,4 @@
!!!
html
head
title Jade Example
link(rel="stylesheet", href="/stylesheets/style.css")
include header
body!= body
+29 -9
Ver Arquivo
@@ -3,29 +3,49 @@
* Module dependencies.
*/
var express = require('../../lib/express');
var express = require('../../lib/express')
, url = require('url');
var app = express.createServer();
app.set('views', __dirname + '/views');
// set default layout, usually "layout"
app.set('view options', { layout: 'layouts/default' });
// map .html to ejs module
app.register('html', require('ejs'));
app.set('view engine', 'html');
// Set our default template engine to "ejs"
// which prevents the need for extensions
// (although you can still mix and match)
app.set('view engine', 'ejs');
// set default layout, usually "layout"
app.locals.layout = 'layouts/default';
app.use(function(req, res, next){
// expose the current path as a view local
res.locals.path = url.parse(req.url).pathname;
// assign content str for section
res.locals.contentFor = function(section, str){
res.locals[section] = str;
};
next();
});
app.get('/', function(req, res){
res.render('pages/default');
res.render('page');
});
app.get('/alternate', function(req, res){
res.render('page', { layout: 'layouts/alternate' });
});
app.get('/alternate2', function(req, res){
res.render('page2');
});
app.get('/defined-in-view', function(req, res){
// note that we do not explicitly
// state the layout here, the view does,
// although we could do it here as well.
res.render('pages/alternate');
res.render('pages');
});
app.listen(3000);
@@ -0,0 +1 @@
<p>Moar sidebar here</p>
@@ -1,6 +0,0 @@
<html>
<body>
<h1>Alternate Layout</h1>
<%- body %>
</body>
</html>
@@ -0,0 +1,26 @@
<html>
<title>Alternate</title>
<style>
body {
padding: 50px;
font: 14px "helvetica neue", helvetica, sans-serif;
color: #333;
}
#sidebar {
float: left;
width: 150px;
}
#content {
float: left;
}
</style>
<body>
<h1>Alternate Layout</h1>
<div id="sidebar">
<%- sidebar %>
</div>
<div id="content">
<%- body %>
</div>
</body>
</html>
@@ -1,6 +0,0 @@
<html>
<body>
<h1>Default Layout</h1>
<%- body %>
</body>
</html>
@@ -0,0 +1,16 @@
<html>
<head>
<title>Default</title>
<style>
body {
padding: 50px;
font: 14px "helvetica neue", helvetica, sans-serif;
color: #333;
}
</style>
</head>
<body>
<h1>Default Layout</h1>
<%- body %>
</body>
</html>
+8
Ver Arquivo
@@ -0,0 +1,8 @@
<h1>Page</h1>
<% if (path == '/alternate') { %>
<% contentFor('sidebar', partial('alternate-sidebar')) %>
<p>Click <a href="/">here</a> to view the default layout.</p>
<p>Click <a href="/alternate2">here</a> to view another alternate page.</p>
<% } else { %>
<p>Click <a href="/alternate">here</a> to view the alternate layout.</p>
<% } %>
+4
Ver Arquivo
@@ -0,0 +1,4 @@
<% layout('layouts/alternate') %>
<% contentFor('sidebar', '<p>Another sidebar here</p>') %>
<h1>Page</h1>
<p>Click <a href="/">here</a> to view the default layout.</p>
@@ -1,2 +0,0 @@
<% layout('layouts/alternate') %>
<h1>Page</h1>
@@ -1 +0,0 @@
<h1>Page</h1>
-36
Ver Arquivo
@@ -1,36 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../../lib/express')
, md = require('node-markdown').Markdown;
var app = express.createServer();
// register .md so that markdown may comply
// with the express view system by implementing
// a .compile() method
app.register('.md', {
compile: function(str, options){
var html = md(str);
return function(locals){
return html.replace(/\{([^}]+)\}/g, function(_, name){
return locals[name];
});
};
}
});
// Optional since express defaults to CWD/views
app.set('views', __dirname + '/views');
app.set('view engine', 'md');
app.get('/', function(req, res){
res.render('index', { layout: false, title: 'Markdown Example' });
});
app.listen(3000);
console.log('Express app started on port 3000');
+45
Ver Arquivo
@@ -0,0 +1,45 @@
/**
* Module dependencies.
*/
var express = require('../../')
, fs = require('fs')
, md = require('github-flavored-markdown').parse;
var app = module.exports = express();
// register .md as an engine in express view system
app.engine('md', function(path, options, fn){
fs.readFile(path, 'utf8', function(err, str){
if (err) return fn(err);
try {
var html = md(str);
html = html.replace(/\{([^}]+)\}/g, function(_, name){
return options[name] || '';
})
fn(null, html);
} catch(err) {
fn(err);
}
});
})
app.set('views', __dirname + '/views');
// make it the default so we dont need .md
app.set('view engine', 'md');
app.get('/', function(req, res){
res.render('index', { title: 'Markdown Example' });
})
app.get('/fail', function(req, res){
res.render('missing', { title: 'Markdown Example' });
})
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
-24
Ver Arquivo
@@ -1,24 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../../lib/express')
, blog = require('../blog/app');
var app = express.createServer();
app.use(express.cookieParser());
app.use(express.session({ secret: 'keyboard cat' }));
// mount the blog. the blog app is written using the "base"
// local variable, allowing it's urls to adjust to wherever
// we wish to mount it.
app.use('/blog', blog);
app.get('/', function(req, res){
res.send('Visit <a href="/blog">/blog</a>');
});
app.listen(3000);
console.log('Server listening on port 3000');
+19 -31
Ver Arquivo
@@ -3,46 +3,34 @@
* Module dependencies.
*/
var express = require('../../lib/express')
, form = require('connect-form');
var express = require('../../')
, format = require('util').format;
var app = express.createServer(
// connect-form (http://github.com/visionmedia/connect-form)
// middleware uses the formidable middleware to parse urlencoded
// and multipart form data
form({ keepExtensions: true })
);
var app = module.exports = express()
// bodyParser in connect 2.x uses node-formidable to parse
// the multipart form data.
app.use(express.bodyParser())
app.get('/', function(req, res){
res.send('<form method="post" enctype="multipart/form-data">'
+ '<p>Title: <input type="text" name="title" /></p>'
+ '<p>Image: <input type="file" name="image" /></p>'
+ '<p><input type="submit" value="Upload" /></p>'
+ '</form>');
});
app.post('/', function(req, res, next){
// connect-form adds the req.form object
// we can (optionally) define onComplete, passing
// the exception (if any) fields parsed, and files parsed
req.form.complete(function(err, fields, files){
if (err) {
next(err);
} else {
console.log('\nuploaded %s to %s'
, files.image.filename
, files.image.path);
res.redirect('back');
}
});
// We can add listeners for several form
// events such as "progress"
req.form.on('progress', function(bytesReceived, bytesExpected){
var percent = (bytesReceived / bytesExpected * 100) | 0;
process.stdout.write('Uploading: %' + percent + '\r');
});
// the uploaded file can be found as `req.files.image` and the
// title field as `req.body.title`
res.send(format('\nuploaded %s (%d Kb) to %s as %s'
, req.files.image.name
, req.files.image.size / 1024 | 0
, req.files.image.path
, req.body.title));
});
app.listen(3000);
console.log('Express app started on port 3000');
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
+1 -2
Ver Arquivo
@@ -23,8 +23,7 @@ function bootApplication(app) {
app.use(express.static(__dirname + '/public'));
// Example 500 page
app.error(function(err, req, res){
console.dir(err)
app.use(function(err, req, res, next){
res.render('500');
});
+14 -5
Ver Arquivo
@@ -3,8 +3,8 @@
* Module dependencies.
*/
var express = require('../../lib/express')
, app = express.createServer();
var express = require('../../')
, app = module.exports = express();
// Faux database
@@ -18,7 +18,14 @@ var users = [
// Convert :to and :from to integers
app.param(['to', 'from'], function(n){ return parseInt(n, 10); });
app.param(['to', 'from'], function(req, res, next, num, name){
req.params[name] = num = parseInt(num, 10);
if( isNaN(num) ){
next(new Error('failed to parseInt '+num));
} else {
next();
}
});
// Load user by id
@@ -57,5 +64,7 @@ app.get('/users/:from-:to', function(req, res, next){
res.send('users ' + names.slice(from, to).join(', '));
});
app.listen(3000);
console.log('Express application listening on port 3000');
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
+6 -4
Ver Arquivo
@@ -3,9 +3,9 @@
* Module dependencies.
*/
var express = require('../../lib/express');
var express = require('../../');
var app = express.createServer();
var app = module.exports = express();
// Ad-hoc example resource method
@@ -85,5 +85,7 @@ app.get('/', function(req, res){
].join('\n'));
});
app.listen(3000);
console.log('Express app started on port 3000');
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
+21
Ver Arquivo
@@ -0,0 +1,21 @@
/**
* Module dependencies.
*/
var express = require('../../lib/express')
, redis = require('redis')
, app = express.createServer()
, db = { users: [] };
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
// pretend db is a database, could be
// whatever you like
require('./boot')(app, db);
app.listen(3000);
console.log('Express app started on port 3000');
+26
Ver Arquivo
@@ -0,0 +1,26 @@
/**
* Module dependencies.
*/
var vm = require('vm')
, fs = require('fs');
module.exports = function(app, db){
var dir = __dirname + '/routes';
// grab a list of our route files
fs.readdirSync(dir).forEach(function(file){
var str = fs.readFileSync(dir + '/' + file, 'utf8');
// inject some pseudo globals by evaluating
// the file with vm.runInNewContext()
// instead of loading it with require(). require's
// internals use similar, so dont be afraid of "boot time".
var context = { app: app, db: db };
// we have to merge the globals for console, process etc
for (var key in global) context[key] = global[key];
// note that this is essentially no different than ... just using
// global variables, though it's only YOUR code that could influence
// them, which is a bonus.
vm.runInNewContext(str, context, file);
});
};
+4
Ver Arquivo
@@ -0,0 +1,4 @@
app.get('/', function(req, res){
res.render('index');
});
+20
Ver Arquivo
@@ -0,0 +1,20 @@
app.redirect('user list', '/users');
app.get('/users', function(req, res){
res.render('user/list', { users: db.users });
});
app.get('/user/add', function(req, res){
res.render('user/add');
});
app.post('/user', function(req, res){
var user = req.body.user;
db.users.push(user);
res.redirect('user list');
});
app.get('/user/:id', function(req, res){
res.render('user');
});
+4
Ver Arquivo
@@ -0,0 +1,4 @@
h2 Route sharing example
ul
li: a(href='/user/add') Add user
li: a(href='/users') User list
+11
Ver Arquivo
@@ -0,0 +1,11 @@
doctype html
html
head
title Route loading example
style
body {
padding: 50px;
font: 14px/1.5 solid helvetica, arial, sans-serif;
}
body
#content!= body
+5
Ver Arquivo
@@ -0,0 +1,5 @@
h2 Add a user
form(action='/user', method='post')
p: input(type='text', name='user[name]', placeholder='Username')
p: input(type='text', name='user[email]', placeholder='Email')
p: input(type='submit', value='Add')
@@ -0,0 +1,6 @@
h1= user.name
table
tbody
tr
td Email
td= user.email
@@ -0,0 +1,5 @@
h1 Users
- if (users.length)
!= partial('user', users)
- else
p No users, head over to <a href='/user/add'>/user/add</a> to create one.
+2 -3
Ver Arquivo
@@ -1,4 +1,3 @@
/**
* Module dependencies.
*/
@@ -40,7 +39,7 @@ function andRestrictToSelf(req, res, next) {
} else {
// You may want to implement specific exceptions
// such as UnauthorizedError or similar so that you
// can handle these in app.error() specifically
// can handle these can be special-cased in an error handler
// (view ./examples/pages for this)
next(new Error('Unauthorized'));
}
@@ -59,7 +58,7 @@ function andRestrictTo(role) {
// Middleware for faux authentication
// you would of course implement something real,
// but this illustrates how an authenticated user
// may interacte with middleware
// may interact with middleware
app.use(function(req, res, next){
req.authenticatedUser = users[0];
@@ -3,29 +3,37 @@
* Module dependencies.
*/
var express = require('../../lib/express');
var express = require('../../');
var app = express.createServer();
var app = module.exports = express();
// configuration
// create an error with .status. we
// can then use the property in our
// custom error handler (Connect repects this prop as well)
function error(status, msg) {
var err = new Error(msg);
err.status = status;
return err;
}
// if we wanted to supply more than JSON, we could
// use something similar to the content-negotiation
// example.
// here we validate the API key,
// by mounting this middleware to /api/v1
// meaning only paths prefixed with "/api/v1"
// by mounting this middleware to /api
// meaning only paths prefixed with "/api"
// will cause this middleware to be invoked
app.use('/api/v1', function(req, res, next){
app.use('/api', function(req, res, next){
var key = req.query['api-key'];
// key isnt present
if (!key) return next(new Error('api key required'));
if (!key) return next(error(400, 'api key required'));
// key is invalid
if (!~apiKeys.indexOf(key)) return next(new Error('invalid api key'));
if (!~apiKeys.indexOf(key)) return next(error(401, 'invalid api key'));
// all good, store req.key for route access
req.key = key;
@@ -44,39 +52,23 @@ app.use(app.router);
// regular middleware.
app.use(function(err, req, res, next){
// whatever you want here, feel free to populate
// properties on `err` to treat it differently in here,
// or when you next(err) set res.statusCode= etc.
res.send({ error: err.message }, 500);
// properties on `err` to treat it differently in here.
res.send(err.status || 500, { error: err.message });
});
// our custom JSON 404 middleware. Since it's placed last
// it will be the last middleware called, if all others
// invoke next() and do not respond.
app.use(function(req, res){
res.send({ error: "Lame, can't find that" }, 404);
res.send(404, { error: "Lame, can't find that" });
});
/**
* Generate our unique identifier.
*/
function uid() {
return [
Math.random() * 0xffff | 0
, Math.random() * 0xffff | 0
, Math.random() * 0xffff | 0
, Date.now()
].join('-');
}
// map of valid api keys, typically mapped to
// account info with some sort of database like redis.
// api keys do _not_ serve as authentication, merely to
// track API usage or help prevent malicious behavior etc.
var apiKeys = [uid(), uid(), uid()];
console.log('valid keys:\n ', apiKeys.join('\n '));
var apiKeys = ['foo', 'bar', 'baz'];
// these two objects will serve as our faux database
@@ -101,15 +93,15 @@ var userRepos = {
// we now can assume the api key is valid,
// and simply expose the data
app.get('/api/v1/users', function(req, res, next){
app.get('/api/users', function(req, res, next){
res.send(users);
});
app.get('/api/v1/repos', function(req, res, next){
app.get('/api/repos', function(req, res, next){
res.send(repos);
});
app.get('/api/v1/user/:name/repos', function(req, res, next){
app.get('/api/user/:name/repos', function(req, res, next){
var name = req.params.name
, user = userRepos[name];
@@ -117,5 +109,7 @@ app.get('/api/v1/user/:name/repos', function(req, res, next){
else next();
});
app.listen(3000);
console.log('Express server listening on port 3000');
if (!module.parent) {
app.listen(3000);
console.log('Express server listening on port 3000');
}
+3 -1
Ver Arquivo
@@ -1,2 +1,4 @@
module.exports = require('./lib/express');
module.exports = process.env.EXPRESS_COV
? require('./lib-cov/express')
: require('./lib/express');
+535
Ver Arquivo
@@ -0,0 +1,535 @@
/*!
* Express - proto
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var connect = require('connect')
, Router = require('./router')
, methods = Router.methods.concat('del', 'all')
, middleware = require('./middleware')
, debug = require('debug')('express:application')
, View = require('./view')
, url = require('url')
, utils = connect.utils
, path = require('path')
, http = require('http')
, join = path.join
, fs = require('fs');
/**
* Application prototype.
*/
var app = exports = module.exports = {};
/**
* Initialize the server.
*
* - setup default configuration
* - setup default middleware
* - setup route reflection methods
*
* @api private
*/
app.init = function(){
var self = this;
this.cache = {};
this.settings = {};
this.engines = {};
this.viewCallbacks = [];
this.defaultConfiguration();
// route reflection methods
methods.forEach(function(method){
self.lookup[method] = function(path){
return self._router.lookup(method, path);
};
self.remove[method] = function(path){
return self._router.lookup(method, path).remove();
};
});
// del -> delete
self.lookup.del = self.lookup.delete;
self.remove.del = self.remove.delete;
};
/**
* Initialize application configuration.
*
* @api private
*/
app.defaultConfiguration = function(){
var self = this;
// default settings
this.set('env', process.env.NODE_ENV || 'development');
debug('booting in %s mode', this.get('env'));
// implicit middleware
this.use(connect.query());
this.use(middleware.init(this));
// app locals
this.locals = function(obj){
for (var key in obj) self.locals[key] = obj[key];
return self;
};
// response locals
this.locals.use = function(fn){
if (3 == fn.length) {
self.viewCallbacks.push(fn);
} else {
self.viewCallbacks.push(function(req, res, done){
fn(req, res);
done();
});
}
return this;
};
// router
this._router = new Router(this);
this.routes = this._router.routes;
this.__defineGetter__('router', function(){
this._usedRouter = true;
this._router.caseSensitive = this.enabled('case sensitive routing');
this._router.strict = this.enabled('strict routing');
return this._router.middleware;
});
// default locals
this.locals.settings = this.settings;
// default configuration
this.enable('jsonp callback');
this.configure('development', function(){
this.set('json spaces', 2);
});
this.configure('production', function(){
this.enable('view cache');
});
};
/**
* Remove routes matching the given `path`.
*
* @param {Route} path
* @return {Boolean}
* @api public
*/
app.remove = function(path){
return this._router.lookup('all', path).remove();
};
/**
* Lookup routes defined with a path
* equivalent to `path`.
*
* @param {String} path
* @return {Array}
* @api public
*/
app.lookup = function(path){
return this._router.lookup('all', path);
};
/**
* Proxy `connect#use()` to apply settings to
* mounted applications.
*
* @param {String|Function|Server} route
* @param {Function|Server} fn
* @return {app} for chaining
* @api public
*/
app.use = function(route, fn){
var app, home, handle;
// default route to '/'
if ('string' != typeof route) fn = route, route = '/';
// express app
if (fn.handle && fn.set) app = fn;
// restore .app property on req and res
if (app) {
app.route = route;
fn = function(req, res, next) {
var orig = req.app;
app.handle(req, res, function(err){
req.app = res.app = orig;
next(err);
});
};
}
connect.proto.use.call(this, route, fn);
// mounted an app
if (app) {
app.parent = this;
app.emit('mount', this);
}
return this;
};
/**
* Register the given template engine callback `fn`
* as `ext`. For example we may wish to map ".html"
* files to ejs rather than using the ".ejs" extension.
*
* app.engine('.html', require('ejs').render);
*
* or
*
* app.engine('html', require('ejs').render);
*
* @param {String} ext
* @param {Function} fn
* @return {app} for chaining
* @api public
*/
app.engine = function(ext, fn){
if ('function' != typeof fn) throw new Error('callback function required');
if ('.' != ext[0]) ext = '.' + ext;
this.engines[ext] = fn;
return this;
};
/**
* Map the given param placeholder `name`(s) to the given callback(s).
*
* Param mapping is used to provide pre-conditions to routes
* which us normalized placeholders. This callback has the same
* signature as regular middleware, for example below when ":userId"
* is used this function will be invoked in an attempt to load the user.
*
* app.param('userId', function(req, res, next, id){
* User.find(id, function(err, user){
* if (err) {
* next(err);
* } else if (user) {
* req.user = user;
* next();
* } else {
* next(new Error('failed to load user'));
* }
* });
* });
*
* Passing a single function allows you to map logic
* to the values passed to `app.param()`, for example
* this is useful to provide coercion support in a concise manner.
*
* The following example maps regular expressions to param values
* ensuring that they match, otherwise passing control to the next
* route:
*
* app.param(function(name, regexp){
* if (regexp instanceof RegExp) {
* return function(req, res, next, val){
* var captures;
* if (captures = regexp.exec(String(val))) {
* req.params[name] = captures;
* next();
* } else {
* next('route');
* }
* }
* }
* });
*
* We can now use it as shown below, where "/commit/:commit" expects
* that the value for ":commit" is at 5 or more digits. The capture
* groups are then available as `req.params.commit` as we defined
* in the function above.
*
* app.param('commit', /^\d{5,}$/);
*
* For more of this useful functionality take a look
* at [express-params](http://github.com/visionmedia/express-params).
*
* @param {String|Array|Function} name
* @param {Function} fn
* @return {app} for chaining
* @api public
*/
app.param = function(name, fn){
var self = this
, fns = [].slice.call(arguments, 1);
// array
if (Array.isArray(name)) {
name.forEach(function(name){
fns.forEach(function(fn){
self.param(name, fn);
});
});
// param logic
} else if ('function' == typeof name) {
this._router.param(name);
// single
} else {
if (':' == name[0]) name = name.substr(1);
fns.forEach(function(fn){
self._router.param(name, fn);
});
}
return this;
};
/**
* Assign `setting` to `val`, or return `setting`'s value.
* Mounted servers inherit their parent server's settings.
*
* @param {String} setting
* @param {String} val
* @return {Server|Mixed} for chaining, or the setting value
* @api public
*/
app.set = function(setting, val){
if (1 == arguments.length) {
if (this.settings.hasOwnProperty(setting)) {
return this.settings[setting];
} else if (this.parent) {
return this.parent.set(setting);
}
} else {
this.settings[setting] = val;
return this;
}
};
/**
* Return the app's absolute pathname
* based on the parent(s) that have
* mounted it.
*
* @return {String}
* @api private
*/
app.path = function(){
return this.parent
? this.parent.path() + this.route
: '';
};
/**
* Check if `setting` is enabled.
*
* @param {String} setting
* @return {Boolean}
* @api public
*/
app.enabled = function(setting){
return !!this.set(setting);
};
/**
* Check if `setting` is disabled.
*
* @param {String} setting
* @return {Boolean}
* @api public
*/
app.disabled = function(setting){
return !this.set(setting);
};
/**
* Enable `setting`.
*
* @param {String} setting
* @return {app} for chaining
* @api public
*/
app.enable = function(setting){
return this.set(setting, true);
};
/**
* Disable `setting`.
*
* @param {String} setting
* @return {app} for chaining
* @api public
*/
app.disable = function(setting){
return this.set(setting, false);
};
/**
* Configure callback for zero or more envs,
* when no env is specified that callback will
* be invoked for all environments. Any combination
* can be used multiple times, in any order desired.
*
* Examples:
*
* app.configure(function(){
* // executed for all envs
* });
*
* app.configure('stage', function(){
* // executed staging env
* });
*
* app.configure('stage', 'production', function(){
* // executed for stage and production
* });
*
* @param {String} env...
* @param {Function} fn
* @return {app} for chaining
* @api public
*/
app.configure = function(env, fn){
var envs = 'all'
, args = [].slice.call(arguments);
fn = args.pop();
if (args.length) envs = args;
if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this);
return this;
};
/**
* Listen for connections.
*
* This method takes the same arguments
* as node's `http.Server#listen()`.
*
* @return {http.Server}
* @api public
*/
app.listen = function(){
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
/**
* Delegate `.VERB(...)` calls to `.route(VERB, ...)`.
*/
methods.forEach(function(method){
app[method] = function(path){
if ('get' == method && 1 == arguments.length) return this.set(path);
var args = [method].concat([].slice.call(arguments));
if (!this._usedRouter) this.use(this.router);
return this._router.route.apply(this._router, args);
}
});
/**
* Special-cased "all" method, applying the given route `path`,
* middleware, and callback to _every_ HTTP method.
*
* @param {String} path
* @param {Function} ...
* @return {app} for chaining
* @api public
*/
app.all = function(path){
var args = arguments;
methods.forEach(function(method){
if ('all' == method || 'del' == method) return;
app[method].apply(this, args);
}, this);
return this;
};
// del -> delete alias
app.del = app.delete;
/**
* Render the given view `name` name with `options`
* and a callback accepting an error and the
* rendered template string.
*
* @param {String} name
* @param {String|Function} options or fn
* @param {Function} fn
* @api public
*/
app.render = function(name, options, fn){
var self = this
, opts = {}
, cache = this.cache
, engines = this.engines
, view;
// support callback function as second arg
if ('function' == typeof options) {
fn = options, options = {};
}
// merge app.locals
utils.merge(opts, this.locals);
// merge options.locals
if (options.locals) utils.merge(opts, options.locals);
// merge options
utils.merge(opts, options);
// set .cache unless explicitly provided
opts.cache = null == opts.cache
? this.enabled('view cache')
: opts.cache;
// primed cache
if (opts.cache) view = cache[name];
// view
if (!view) {
view = new View(name, {
defaultEngine: this.get('view engine')
, root: this.get('views') || process.cwd() + '/views'
, engines: engines
});
if (!view.path) {
return fn(new Error('Failed to lookup view "' + name + '"'));
}
// prime the cache
if (opts.cache) cache[name] = view;
}
// render
try {
view.render(opts, fn);
} catch (err) {
fn(err);
}
};
+43 -37
Ver Arquivo
@@ -9,69 +9,75 @@
* Module dependencies.
*/
var connect = require('connect')
, HTTPSServer = require('./https')
, HTTPServer = require('./http')
var http = require('http')
, connect = require('connect')
, proto = require('./application')
, Route = require('./router/route')
, Router = require('./router')
, req = require('./request')
, res = require('./response')
, utils = connect.utils;
/**
* Re-export connect auto-loaders.
*
* This prevents the need to `require('connect')` in order
* to access core middleware, so for example `express.logger()` instead
* of `require('connect').logger()`.
* Expose `createApplication()`.
*/
var exports = module.exports = connect.middleware;
exports = module.exports = createApplication;
/**
* Framework version.
*/
exports.version = '2.4.3';
exports.version = '3.0.0alpha1';
/**
* Shortcut for `new Server(...)`.
* Create an express application.
*
* @param {Function} ...
* @return {Server}
* @return {Function}
* @api public
*/
exports.createServer = function(options){
if ('object' == typeof options) {
return new HTTPSServer(options, Array.prototype.slice.call(arguments, 1));
} else {
return new HTTPServer(Array.prototype.slice.call(arguments));
}
};
function createApplication() {
var app = connect();
utils.merge(app, proto);
app.request = { __proto__: req };
app.response = { __proto__: res };
app.init();
return app;
}
/**
* Expose connect.middleware as express.*
* for example `express.logger` etc.
*/
for (var key in connect.middleware) {
Object.defineProperty(
exports
, key
, Object.getOwnPropertyDescriptor(connect.middleware, key));
}
/**
* Expose the prototypes.
*/
exports.application = proto;
exports.request = req;
exports.response = res;
/**
* Expose constructors.
*/
exports.HTTPServer = HTTPServer;
exports.HTTPSServer = HTTPSServer;
exports.Route = Route;
exports.Router = Router;
/**
* View extensions.
* Expose HTTP methods.
*/
exports.View =
exports.view = require('./view');
/**
* Response extensions.
*/
require('./response');
/**
* Request extensions.
*/
require('./request');
exports.methods = require('./router/methods');
// Error handler title
-544
Ver Arquivo
@@ -1,544 +0,0 @@
/*!
* Express - HTTPServer
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var qs = require('qs')
, connect = require('connect')
, router = require('./router')
, Router = require('./router')
, view = require('./view')
, toArray = require('./utils').toArray
, methods = router.methods.concat('del', 'all')
, url = require('url')
, utils = connect.utils;
/**
* Expose `HTTPServer`.
*/
exports = module.exports = HTTPServer;
/**
* Server proto.
*/
var app = HTTPServer.prototype;
/**
* Initialize a new `HTTPServer` with optional `middleware`.
*
* @param {Array} middleware
* @api public
*/
function HTTPServer(middleware){
connect.HTTPServer.call(this, []);
this.init(middleware);
};
/**
* Inherit from `connect.HTTPServer`.
*/
app.__proto__ = connect.HTTPServer.prototype;
/**
* Initialize the server.
*
* @param {Array} middleware
* @api private
*/
app.init = function(middleware){
var self = this;
this.cache = {};
this.settings = {};
this.redirects = {};
this.isCallbacks = {};
this._locals = {};
this.dynamicViewHelpers = {};
this.errorHandlers = [];
this.set('home', '/');
this.set('env', process.env.NODE_ENV || 'development');
// expose objects to each other
this.use(function(req, res, next){
req.query = req.query || {};
res.setHeader('X-Powered-By', 'Express');
req.app = res.app = self;
req.res = res;
res.req = req;
req.next = next;
// assign req.query
if (req.url.indexOf('?') > 0) {
var query = url.parse(req.url).query;
req.query = qs.parse(query);
}
next();
});
// apply middleware
if (middleware) middleware.forEach(self.use.bind(self));
// router
this.routes = new Router(this);
this.__defineGetter__('router', function(){
this.__usedRouter = true;
return self.routes.middleware;
});
// default locals
this.locals({
settings: this.settings
, app: this
});
// default development configuration
this.configure('development', function(){
this.enable('hints');
});
// default production configuration
this.configure('production', function(){
this.enable('view cache');
});
// register error handlers on "listening"
// so that they disregard definition position.
this.on('listening', this.registerErrorHandlers.bind(this));
// route manipulation methods
methods.forEach(function(method){
self.lookup[method] = function(path){
return self.routes.lookup(method, path);
};
self.match[method] = function(path){
return self.routes.match(method, path);
};
self.remove[method] = function(path){
return self.routes.lookup(method, path).remove();
};
});
// del -> delete
self.lookup.del = self.lookup.delete;
self.match.del = self.match.delete;
self.remove.del = self.remove.delete;
};
/**
* Remove routes matching the given `path`.
*
* @param {Route} path
* @return {Boolean}
* @api public
*/
app.remove = function(path){
return this.routes.lookup('all', path).remove();
};
/**
* Lookup routes defined with a path
* equivalent to `path`.
*
* @param {Stirng} path
* @return {Array}
* @api public
*/
app.lookup = function(path){
return this.routes.lookup('all', path);
};
/**
* Lookup routes matching the given `url`.
*
* @param {Stirng} url
* @return {Array}
* @api public
*/
app.match = function(url){
return this.routes.match('all', url);
};
/**
* When using the vhost() middleware register error handlers.
*/
app.onvhost = function(){
this.registerErrorHandlers();
};
/**
* Register error handlers.
*
* @return {Server} for chaining
* @api public
*/
app.registerErrorHandlers = function(){
this.errorHandlers.forEach(function(fn){
this.use(function(err, req, res, next){
fn.apply(this, arguments);
});
}, this);
return this;
};
/**
* Proxy `connect.HTTPServer#use()` to apply settings to
* mounted applications.
*
* @param {String|Function|Server} route
* @param {Function|Server} middleware
* @return {Server} for chaining
* @api public
*/
app.use = function(route, middleware){
var app, home, handle;
if ('string' != typeof route) {
middleware = route, route = '/';
}
// express app
if (middleware.handle && middleware.set) app = middleware;
// restore .app property on req and res
if (app) {
app.route = route;
middleware = function(req, res, next) {
var orig = req.app;
app.handle(req, res, function(err){
req.app = res.app = orig;
next(err);
});
};
}
connect.HTTPServer.prototype.use.call(this, route, middleware);
// mounted an app, invoke the hook
// and adjust some settings
if (app) {
home = app.set('home');
if ('/' == home) home = '';
app.set('home', app.route + home);
app.parent = this;
if (app.__mounted) app.__mounted.call(app, this);
}
return this;
};
/**
* Assign a callback `fn` which is called
* when this `Server` is passed to `Server#use()`.
*
* Examples:
*
* var app = express.createServer()
* , blog = express.createServer();
*
* blog.mounted(function(parent){
* // parent is app
* // "this" is blog
* });
*
* app.use(blog);
*
* @param {Function} fn
* @return {Server} for chaining
* @api public
*/
app.mounted = function(fn){
this.__mounted = fn;
return this;
};
/**
* See: view.register.
*
* @return {Server} for chaining
* @api public
*/
app.register = function(){
view.register.apply(this, arguments);
return this;
};
/**
* Register the given view helpers `obj`. This method
* can be called several times to apply additional helpers.
*
* @param {Object} obj
* @return {Server} for chaining
* @api public
*/
app.helpers =
app.locals = function(obj){
utils.merge(this._locals, obj);
return this;
};
/**
* Register the given dynamic view helpers `obj`. This method
* can be called several times to apply additional helpers.
*
* @param {Object} obj
* @return {Server} for chaining
* @api public
*/
app.dynamicHelpers = function(obj){
utils.merge(this.dynamicViewHelpers, obj);
return this;
};
/**
* Map the given param placeholder `name`(s) to the given callback `fn`.
*
* Param mapping is used to provide pre-conditions to routes
* which us normalized placeholders. This callback has the same
* signature as regular middleware, for example below when ":userId"
* is used this function will be invoked in an attempt to load the user.
*
* app.param('userId', function(req, res, next, id){
* User.find(id, function(err, user){
* if (err) {
* next(err);
* } else if (user) {
* req.user = user;
* next();
* } else {
* next(new Error('failed to load user'));
* }
* });
* });
*
* @param {String|Array|Function} name
* @param {Function} fn
* @return {Server} for chaining
* @api public
*/
app.param = function(name, fn){
// array
if (Array.isArray(name)) {
name.forEach(function(name){
this.param(name, fn);
}, this);
// param logic
} else if ('function' == typeof name) {
this.routes.param(name);
// single
} else {
if (':' == name[0]) name = name.substr(1);
this.routes.param(name, fn);
}
return this;
};
/**
* Assign a custom exception handler callback `fn`.
* These handlers are always _last_ in the middleware stack.
*
* @param {Function} fn
* @return {Server} for chaining
* @api public
*/
app.error = function(fn){
this.errorHandlers.push(fn);
return this;
};
/**
* Register the given callback `fn` for the given `type`.
*
* @param {String} type
* @param {Function} fn
* @return {Server} for chaining
* @api public
*/
app.is = function(type, fn){
if (!fn) return this.isCallbacks[type];
this.isCallbacks[type] = fn;
return this;
};
/**
* Assign `setting` to `val`, or return `setting`'s value.
* Mounted servers inherit their parent server's settings.
*
* @param {String} setting
* @param {String} val
* @return {Server|Mixed} for chaining, or the setting value
* @api public
*/
app.set = function(setting, val){
if (val === undefined) {
if (this.settings.hasOwnProperty(setting)) {
return this.settings[setting];
} else if (this.parent) {
return this.parent.set(setting);
}
} else {
this.settings[setting] = val;
return this;
}
};
/**
* Check if `setting` is enabled.
*
* @param {String} setting
* @return {Boolean}
* @api public
*/
app.enabled = function(setting){
return !!this.set(setting);
};
/**
* Check if `setting` is disabled.
*
* @param {String} setting
* @return {Boolean}
* @api public
*/
app.disabled = function(setting){
return !this.set(setting);
};
/**
* Enable `setting`.
*
* @param {String} setting
* @return {Server} for chaining
* @api public
*/
app.enable = function(setting){
return this.set(setting, true);
};
/**
* Disable `setting`.
*
* @param {String} setting
* @return {Server} for chaining
* @api public
*/
app.disable = function(setting){
return this.set(setting, false);
};
/**
* Redirect `key` to `url`.
*
* @param {String} key
* @param {String} url
* @return {Server} for chaining
* @api public
*/
app.redirect = function(key, url){
this.redirects[key] = url;
return this;
};
/**
* Configure callback for zero or more envs,
* when no env is specified that callback will
* be invoked for all environments. Any combination
* can be used multiple times, in any order desired.
*
* Examples:
*
* app.configure(function(){
* // executed for all envs
* });
*
* app.configure('stage', function(){
* // executed staging env
* });
*
* app.configure('stage', 'production', function(){
* // executed for stage and production
* });
*
* @param {String} env...
* @param {Function} fn
* @return {Server} for chaining
* @api public
*/
app.configure = function(env, fn){
var envs = 'all'
, args = toArray(arguments);
fn = args.pop();
if (args.length) envs = args;
if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this);
return this;
};
/**
* Delegate `.VERB(...)` calls to `.route(VERB, ...)`.
*/
methods.forEach(function(method){
app[method] = function(path){
if (1 == arguments.length) return this.routes.lookup(method, path);
var args = [method].concat(toArray(arguments));
if (!this.__usedRouter) this.use(this.router);
return this.routes._route.apply(this.routes, args);
}
});
/**
* Special-cased "all" method, applying the given route `path`,
* middleware, and callback to _every_ HTTP method.
*
* @param {String} path
* @param {Function} ...
* @return {Server} for chaining
* @api public
*/
app.all = function(path){
var args = arguments;
if (1 == args.length) return this.routes.lookup('all', path);
methods.forEach(function(method){
if ('all' == method) return;
app[method].apply(this, args);
}, this);
return this;
};
// del -> delete alias
app.del = app.delete;
-52
Ver Arquivo
@@ -1,52 +0,0 @@
/*!
* Express - HTTPSServer
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var connect = require('connect')
, HTTPServer = require('./http')
, https = require('https');
/**
* Expose `HTTPSServer`.
*/
exports = module.exports = HTTPSServer;
/**
* Server proto.
*/
var app = HTTPSServer.prototype;
/**
* Initialize a new `HTTPSServer` with the
* given `options`, and optional `middleware`.
*
* @param {Object} options
* @param {Array} middleware
* @api public
*/
function HTTPSServer(options, middleware){
connect.HTTPSServer.call(this, options, []);
this.init(middleware);
};
/**
* Inherit from `connect.HTTPSServer`.
*/
app.__proto__ = connect.HTTPSServer.prototype;
// mixin HTTPServer methods
Object.keys(HTTPServer.prototype).forEach(function(method){
app[method] = HTTPServer.prototype[method];
});
+37
Ver Arquivo
@@ -0,0 +1,37 @@
/*!
* Express - middleware - init
* Copyright(c) 2010-2011 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* Initialization middleware, exposing the
* request and response to eachother, as well
* as defaulting the X-Powered-By header field.
*
* @param {Function} app
* @return {Function}
* @api private
*/
exports.init = function(app){
return function expressInit(req, res, next){
var charset;
res.setHeader('X-Powered-By', 'Express');
req.app = res.app = app;
req.res = res;
res.req = req;
req.next = next;
req.__proto__ = app.request;
res.__proto__ = app.response;
res.locals = function(obj){
for (var key in obj) res.locals[key] = obj[key];
return res;
};
next();
}
};
+278 -172
Ver Arquivo
@@ -10,24 +10,21 @@
*/
var http = require('http')
, req = http.IncomingMessage.prototype
, utils = require('./utils')
, connect = require('connect')
, parse = require('url').parse
, mime = require('mime');
/**
* Default flash formatters.
*
* @type Object
* Request prototype.
*/
var flashFormatters = exports.flashFormatters = {
s: function(val){
return String(val);
}
var req = exports = module.exports = {
__proto__: http.IncomingMessage.prototype
};
/**
* Return request header or optional default.
* Return request header.
*
* The `Referrer` header field is special-cased,
* both `Referrer` and `Referer` will yield are
@@ -35,122 +32,193 @@ var flashFormatters = exports.flashFormatters = {
*
* Examples:
*
* req.header('Content-Type');
* req.get('Content-Type');
* // => "text/plain"
*
* req.header('content-type');
* req.get('content-type');
* // => "text/plain"
*
* req.header('Accept');
* req.get('Something');
* // => undefined
*
* req.header('Accept', 'text/html');
* // => "text/html"
*
* @param {String} name
* @param {String} defaultValue
* @return {String}
* @api public
*/
req.header = function(name, defaultValue){
req.get = function(name){
switch (name = name.toLowerCase()) {
case 'referer':
case 'referrer':
return this.headers.referrer
|| this.headers.referer
|| defaultValue;
|| this.headers.referer;
default:
return this.headers[name] || defaultValue;
return this.headers[name];
}
};
/**
* Get `field`'s `param` value, defaulting to ''.
* Check if the given `type(s)` is acceptable, returning
* the best match when true, otherwise `undefined`, in which
* case you should respond with 406 "Not Acceptable".
*
* Examples:
*
* req.get('content-disposition', 'filename');
* // => "something.png"
*
* @param {String} field
* @param {String} param
* @return {String}
* @api public
*/
req.get = function(field, param){
var val = this.header(field);
if (!val) return '';
var regexp = new RegExp(param + ' *= *(?:"([^"]+)"|([^;]+))', 'i');
if (!regexp.exec(val)) return '';
return RegExp.$1 || RegExp.$2;
};
/**
* Check if the _Accept_ header is present, and includes the given `type`.
*
* When the _Accept_ header is not present `true` is returned. Otherwise
* the given `type` is matched by an exact match, and then subtypes. You
* may pass the subtype such as "html" which is then converted internally
* to "text/html" using the mime lookup table.
* The `type` value may be a single mime type string
* such as "application/json", the extension name
* such as "json", a comma-delimted list such as "json, html, text/plain",
* or an array `["json", "html", "text/plain"]`. When a list
* or array is given the _best_ match, if any is returned.
*
* Examples:
*
* // Accept: text/html
* req.accepts('html');
* // => true
* // => "html"
*
* // Accept: text/*; application/json
* // Accept: text/*, application/json
* req.accepts('html');
* // => "html"
* req.accepts('text/html');
* req.accepts('text/plain');
* // => "text/html"
* req.accepts('json, text');
* // => "json"
* req.accepts('application/json');
* // => true
* // => "application/json"
*
* // Accept: text/*, application/json
* req.accepts('image/png');
* req.accepts('png');
* // => false
* // => undefined
*
* @param {String} type
* @return {Boolean}
* // Accept: text/*;q=.5, application/json
* req.accepts(['html', 'json']);
* req.accepts('html, json');
* // => "json"
*
* @param {String|Array} type(s)
* @return {String}
* @api public
*/
req.accepts = function(type){
var accept = this.header('Accept');
// normalize extensions ".json" -> "json"
if (type && '.' == type[0]) type = type.substr(1);
// when Accept does not exist, or is '*/*' return true
if (!accept || '*/*' == accept) {
return true;
} else if (type) {
// allow "html" vs "text/html" etc
if (!~type.indexOf('/')) type = mime.lookup(type);
// check if we have a direct match
if (~accept.indexOf(type)) return true;
// check if we have type/*
type = type.split('/')[0] + '/*';
return !!~accept.indexOf(type);
} else {
return false;
}
return utils.accepts(type, this.get('Accept'));
};
/**
* Check if the given `charset` is acceptable,
* otherwise you should respond with 406 "Not Acceptable".
*
* @param {String} charset
* @return {Boolean}
* @api public
*/
req.acceptsCharset = function(charset){
var accepted = this.acceptedCharsets;
return accepted.length
? ~accepted.indexOf(charset)
: true;
};
/**
* Check if the given `lang` is acceptable,
* otherwise you should respond with 406 "Not Acceptable".
*
* @param {String} lang
* @return {Boolean}
* @api public
*/
req.acceptsLanguage = function(lang){
var accepted = this.acceptedLanguages;
return accepted.length
? ~accepted.indexOf(lang)
: true;
};
/**
* Return an array of Accepted media types
* ordered from highest quality to lowest.
*
* Examples:
*
* [ { value: 'application/json',
* quality: 1,
* type: 'application',
* subtype: 'json' },
* { value: 'text/html',
* quality: 0.5,
* type: 'text',
* subtype: 'html' } ]
*
* @return {Array}
* @api public
*/
req.__defineGetter__('accepted', function(){
var accept = this.get('Accept');
return accept
? utils.parseAccept(accept)
: [];
});
/**
* Return an array of Accepted languages
* ordered from highest quality to lowest.
*
* Examples:
*
* Accept-Language: en;q=.5, en-us
* ['en-us', 'en']
*
* @return {Array}
* @api public
*/
req.__defineGetter__('acceptedLanguages', function(){
var accept = this.get('Accept-Language');
return accept
? utils
.parseQuality(accept)
.map(function(obj){
return obj.value;
})
: [];
});
/**
* Return an array of Accepted charsets
* ordered from highest quality to lowest.
*
* Examples:
*
* Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8
* ['unicode-1-1', 'iso-8859-5']
*
* @return {Array}
* @api public
*/
req.__defineGetter__('acceptedCharsets', function(){
var accept = this.get('Accept-Charset');
return accept
? utils
.parseQuality(accept)
.map(function(obj){
return obj.value;
})
: [];
});
/**
* Return the value of param `name` when present or `defaultValue`.
*
* - Checks body params, ex: id=12, {"id":12}
* - Checks route placeholders, ex: _/user/:id_
* - Checks query string params, ex: ?id=12
* - Checks urlencoded body params, ex: id=12
*
* To utilize urlencoded request bodies, `req.body`
* To utilize request bodies, `req.body`
* should be an object. This can be done by using
* the `connect.bodyParser` middleware.
* the `connect.bodyParser()` middleware.
*
* @param {String} name
* @param {Mixed} defaultValue
@@ -159,80 +227,22 @@ req.accepts = function(type){
*/
req.param = function(name, defaultValue){
// route params like /user/:id
if (this.params && this.params.hasOwnProperty(name) && undefined !== this.params[name]) {
// req.body
if (this.body && undefined !== this.body[name]) return this.body[name];
// route params
if (this.params
&& this.params.hasOwnProperty(name)
&& undefined !== this.params[name]) {
return this.params[name];
}
// query string params
if (undefined !== this.query[name]) {
return this.query[name];
}
// request body params via connect.bodyParser
if (this.body && undefined !== this.body[name]) {
return this.body[name];
}
// query-string
if (undefined !== this.query[name]) return this.query[name];
return defaultValue;
};
/**
* Queue flash `msg` of the given `type`.
*
* Examples:
*
* req.flash('info', 'email sent');
* req.flash('error', 'email delivery failed');
* req.flash('info', 'email re-sent');
* // => 2
*
* req.flash('info');
* // => ['email sent', 'email re-sent']
*
* req.flash('info');
* // => []
*
* req.flash();
* // => { error: ['email delivery failed'], info: [] }
*
* Formatting:
*
* Flash notifications also support arbitrary formatting support.
* For example you may pass variable arguments to `req.flash()`
* and use the %s specifier to be replaced by the associated argument:
*
* req.flash('info', 'email has been sent to %s.', userName);
*
* To add custom formatters use the `exports.flashFormatters` object.
*
* @param {String} type
* @param {String} msg
* @return {Array|Object|Number}
* @api public
*/
req.flash = function(type, msg){
if (this.session === undefined) throw Error('req.flash() requires sessions');
var msgs = this.session.flash = this.session.flash || {};
if (type && msg) {
var i = 2
, args = arguments
, formatters = this.app.flashFormatters || {};
formatters.__proto__ = flashFormatters;
msg = utils.miniMarkdown(utils.escape(msg));
msg = msg.replace(/%([a-zA-Z])/g, function(_, format){
var formatter = formatters[format];
if (formatter) return formatter(args[i++]);
});
return (msgs[type] = msgs[type] || []).push(msg);
} else if (type) {
var arr = msgs[type];
delete msgs[type];
return arr || [];
} else {
this.session.flash = {};
return msgs;
}
};
/**
* Check if the incoming request contains the "Content-Type"
* header field, and it contains the give mime `type`.
@@ -242,30 +252,23 @@ req.flash = function(type, msg){
* // With Content-Type: text/html; charset=utf-8
* req.is('html');
* req.is('text/html');
* req.is('text/*');
* // => true
*
* // When Content-Type is application/json
* req.is('json');
* req.is('application/json');
* req.is('application/*');
* // => true
*
* req.is('html');
* // => false
*
* Ad-hoc callbacks can also be registered with Express, to perform
* assertions again the request, for example if we need an expressive
* way to check if our incoming request is an image, we can register "an image"
* callback:
*
* app.is('an image', function(req){
* return 0 == req.headers['content-type'].indexOf('image');
* });
*
* Now within our route callbacks, we can use to to assert content types
* such as "image/jpeg", "image/png", etc.
*
* app.post('/image/upload', function(req, res, next){
* if (req.is('an image')) {
* if (req.is('image/*')) {
* // do something
* } else {
* next();
@@ -278,25 +281,126 @@ req.flash = function(type, msg){
*/
req.is = function(type){
var fn = this.app.is(type);
if (fn) return fn(this);
var contentType = this.headers['content-type'];
if (!contentType) return;
var ct = this.get('Content-Type');
if (!ct) return false;
ct = ct.split(';')[0];
if (!~type.indexOf('/')) type = mime.lookup(type);
if (~type.indexOf('*')) {
type = type.split('/')
contentType = contentType.split('/');
if ('*' == type[0] && type[1] == contentType[1]) return true;
if ('*' == type[1] && type[0] == contentType[0]) return true;
type = type.split('/');
ct = ct.split('/');
if ('*' == type[0] && type[1] == ct[1]) return true;
if ('*' == type[1] && type[0] == ct[0]) return true;
return false;
}
return !! ~contentType.indexOf(type);
return !! ~ct.indexOf(type);
};
// Callback for isXMLHttpRequest / xhr
/**
* Return the protocol string "http" or "https"
* when requested with TLS. When the "trust proxy"
* setting is enabled the "X-Forwarded-Proto" header
* field will be trusted. If you're running behind
* a reverse proxy that supplies https for you this
* may be enabled.
*
* @return {String}
* @api public
*/
function isxhr() {
return this.header('X-Requested-With', '').toLowerCase() === 'xmlhttprequest';
}
req.__defineGetter__('protocol', function(trustProxy){
var trustProxy = this.app.settings['trust proxy'];
return this.connection.encrypted
? 'https'
: trustProxy
? (this.get('X-Forwarded-Proto') || 'http')
: 'http';
});
/**
* Short-hand for:
*
* req.protocol == 'https'
*
* @return {Boolean}
* @api public
*/
req.__defineGetter__('secure', function(){
return 'https' == this.protocol;
});
/**
* When "trust proxy" is `true`, parse
* the "X-Forwarded-For" ip address list.
*
* For example if the value were "client, proxy1, proxy2"
* you would receive the array `["proxy2", "proxy1", "client"]`
* where "proxy2" is the furthest down-stream.
*
* @return {Array}
* @api public
*/
req.__defineGetter__('ips', function(){
var val = this.get('X-Forwarded-For');
return val
? val.split(/ *, */).reverse()
: [];
});
/**
* Return subdomains as an array.
*
* For example "tobi.ferrets.example.com"
* would provide `["ferrets", "tobi"]`.
*
* @return {Array}
* @api public
*/
req.__defineGetter__('subdomains', function(){
return this.get('Host')
.split('.')
.slice(0, -2)
.reverse();
});
/**
* Short-hand for `require('url').parse(req.url).pathname`.
*
* @return {String}
* @api public
*/
req.__defineGetter__('path', function(){
return parse(this.url).pathname;
});
/**
* Check if the request is fresh, aka
* Last-Modified and/or the ETag
* still match.
*
* @return {Boolean}
* @api public
*/
req.__defineGetter__('fresh', function(){
return ! this.stale;
});
/**
* Check if the request is stale, aka
* "Last-Modified" and / or the "ETag" for the
* resource has changed.
*
* @return {Boolean}
* @api public
*/
req.__defineGetter__('stale', function(){
return connect.utils.modified(this, this.res);
});
/**
* Check if the request was an _XMLHttpRequest_.
@@ -305,5 +409,7 @@ function isxhr() {
* @api public
*/
req.__defineGetter__('isXMLHttpRequest', isxhr);
req.__defineGetter__('xhr', isxhr);
req.__defineGetter__('xhr', function(){
var val = this.get('X-Requested-With') || '';
return 'xmlhttprequest' == val.toLowerCase();
});
+432 -276
Ver Arquivo
@@ -14,131 +14,21 @@ var fs = require('fs')
, path = require('path')
, connect = require('connect')
, utils = connect.utils
, parseRange = require('./utils').parseRange
, res = http.ServerResponse.prototype
, normalizeType = require('./utils').normalizeType
, normalizeTypes = require('./utils').normalizeTypes
, statusCodes = http.STATUS_CODES
, send = connect.static.send
, mime = require('mime')
, basename = path.basename
, extname = path.extname
, join = path.join;
/**
* Send a response with the given `body` and optional `headers` and `status` code.
*
* Examples:
*
* res.send();
* res.send(new Buffer('wahoo'));
* res.send({ some: 'json' });
* res.send('<p>some html</p>');
* res.send('Sorry, cant find that', 404);
* res.send('text', { 'Content-Type': 'text/plain' }, 201);
* res.send(404);
*
* @param {String|Object|Number|Buffer} body or status
* @param {Object|Number} headers or status
* @param {Number} status
* @return {ServerResponse}
* @api public
* Response prototype.
*/
res.send = function(body, headers, status){
// allow status as second arg
if ('number' == typeof headers) {
status = headers,
headers = null;
}
// default status
status = status || this.statusCode;
// allow 0 args as 204
if (!arguments.length || undefined === body) body = status = 204;
// determine content type
switch (typeof body) {
case 'number':
if (!this.header('Content-Type')) {
this.contentType('.txt');
}
body = http.STATUS_CODES[status = body];
break;
case 'string':
if (!this.header('Content-Type')) {
this.charset = this.charset || 'utf-8';
this.contentType('.html');
}
break;
case 'boolean':
case 'object':
if (Buffer.isBuffer(body)) {
if (!this.header('Content-Type')) {
this.contentType('.bin');
}
} else {
return this.json(body, headers, status);
}
break;
}
// populate Content-Length
if (!this.header('Content-Length')) {
this.header('Content-Length', Buffer.isBuffer(body)
? body.length
: Buffer.byteLength(body));
}
// merge headers passed
if (headers) {
var fields = Object.keys(headers);
for (var i = 0, len = fields.length; i < len; ++i) {
var field = fields[i];
this.header(field, headers[field]);
}
}
// strip irrelevant headers
if (204 == status || 304 == status) {
this.removeHeader('Content-Type');
this.removeHeader('Content-Length');
}
// respond
this.statusCode = status;
this.end('HEAD' == this.req.method ? undefined : body);
return this;
};
/**
* Send JSON response with `obj`, optional `headers`, and optional `status`.
*
* Examples:
*
* res.json(null);
* res.json({ user: 'tj' });
* res.json('oh noes!', 500);
* res.json('I dont have that', 404);
*
* @param {Mixed} obj
* @param {Object|Number} headers or status
* @param {Number} status
* @return {ServerResponse}
* @api public
*/
res.json = function(obj, headers, status){
var body = JSON.stringify(obj)
, callback = this.req.query.callback
, jsonp = this.app.enabled('jsonp callback');
this.charset = this.charset || 'utf-8';
this.header('Content-Type', 'application/json');
if (callback && jsonp) {
this.header('Content-Type', 'text/javascript');
body = callback.replace(/[^\w$.]/g, '') + '(' + body + ');';
}
return this.send(body, headers, status);
var res = module.exports = {
__proto__: http.ServerResponse.prototype
};
/**
@@ -155,9 +45,126 @@ res.status = function(code){
};
/**
* Transfer the file at the given `path`. Automatically sets
* the _Content-Type_ response header field. `next()` is called
* when `path` is a directory, or when an error occurs.
* Send a response.
*
* Examples:
*
* res.send(new Buffer('wahoo'));
* res.send({ some: 'json' });
* res.send('<p>some html</p>');
* res.send(404, 'Sorry, cant find that');
* res.send(404);
*
* @param {Mixed} body or status
* @param {Mixed} body
* @return {ServerResponse}
* @api public
*/
res.send = function(body){
var req = this.req
, head = 'HEAD' == req.method;
// allow status / body
if (2 == arguments.length) {
this.statusCode = body;
body = arguments[1];
}
switch (typeof body) {
// response status
case 'number':
this.get('Content-Type') || this.contentType('.txt');
this.statusCode = body;
body = http.STATUS_CODES[body];
break;
// string defaulting to html
case 'string':
if (!this.get('Content-Type')) {
this.charset = this.charset || 'utf-8';
this.contentType('.html');
}
break;
case 'boolean':
case 'object':
if (null == body) {
body = '';
} else if (Buffer.isBuffer(body)) {
this.get('Content-Type') || this.contentType('.bin');
} else {
return this.json(body);
}
break;
}
// populate Content-Length
if (undefined !== body && !this.get('Content-Length')) {
this.set('Content-Length', Buffer.isBuffer(body)
? body.length
: Buffer.byteLength(body));
}
// strip irrelevant headers
if (204 == this.statusCode || 304 == this.statusCode) {
this.removeHeader('Content-Type');
this.removeHeader('Content-Length');
body = '';
}
// respond
this.end(head ? null : body);
return this;
};
/**
* Send JSON response.
*
* Examples:
*
* res.json(null);
* res.json({ user: 'tj' });
* res.json(500, 'oh noes!');
* res.json(404, 'I dont have that');
*
* @param {Mixed} obj or status
* @param {Mixed} obj
* @return {ServerResponse}
* @api public
*/
res.json = function(obj){
// allow status / body
if (2 == arguments.length) {
this.statusCode = obj;
obj = arguments[1];
}
var settings = this.app.settings
, jsonp = settings['jsonp callback']
, replacer = settings['json replacer']
, spaces = settings['json spaces']
, body = JSON.stringify(obj, replacer, spaces)
, callback = this.req.query.callback;
this.charset = this.charset || 'utf-8';
this.set('Content-Type', 'application/json');
if (callback && jsonp) {
this.set('Content-Type', 'text/javascript');
body = callback.replace(/[^\w$.]/g, '') + '(' + body + ');';
}
return this.send(body);
};
/**
* Transfer the file at the given `path`.
*
* Automatically sets the _Content-Type_ response header field.
* The callback `fn(err)` is invoked when the transfer is complete
* or when an error occurs. Be sure to check `res.sentHeader`
* if you wish to attempt responding, as the header and some data
* may have already been transferred.
*
* Options:
*
@@ -171,8 +178,10 @@ res.status = function(code){
*/
res.sendfile = function(path, options, fn){
var next = this.req.next;
options = options || {};
var self = this
, req = self.req
, next = this.req.next
, options = options || {};
// support function as second arg
if ('function' == typeof options) {
@@ -180,32 +189,155 @@ res.sendfile = function(path, options, fn){
options = {};
}
// callback
options.callback = function(err){
if (err) {
// cast ENOENT
if ('ENOENT' == err.code) err = 404;
// coerce numeric error to an Error
// TODO: remove
// TODO: remove docs for headerSent?
if ('number' == typeof err) err = utils.error(err);
// ditch content-disposition to prevent funky responses
if (!self.headerSent) self.removeHeader('Content-Disposition');
// woot! callback available
if (fn) return fn(err);
// lost in limbo if there's no callback
if (self.headerSent) return;
return req.next(err);
}
fn && fn();
};
// transfer
options.path = encodeURIComponent(path);
options.callback = fn;
send(this.req, this, next, options);
};
/**
* Set _Content-Type_ response header passed through `mime.lookup()`.
* Transfer the file at the given `path` as an attachment.
*
* Examples:
* Optionally providing an alternate attachment `filename`,
* and optional callback `fn(err)`. The callback is invoked
* when the data transfer is complete, or when an error has
* ocurred. Be sure to check `res.headerSent` if you plan to respond.
*
* var filename = 'path/to/image.png';
* res.contentType(filename);
* // res.headers['Content-Type'] is now "image/png"
*
* res.contentType('.html');
* res.contentType('html');
* res.contentType('json');
* res.contentType('png');
*
* @param {String} type
* @return {String} the resolved mime type
* @param {String} path
* @param {String|Function} filename or fn
* @param {Function} fn
* @api public
*/
res.contentType = function(type){
return this.header('Content-Type', mime.lookup(type));
res.download = function(path, filename, fn){
// support function as second arg
if ('function' == typeof filename) {
fn = filename;
filename = null;
}
return this.attachment(filename || path).sendfile(path, fn);
};
/**
* Set _Content-Type_ response header with `type` through `mime.lookup()`
* when it does not contain "/", or set the Content-Type to `type` otherwise.
*
* Examples:
*
* res.type('.html');
* res.type('html');
* res.type('json');
* res.type('application/json');
* res.type('png');
*
* @param {String} type
* @return {ServerResponse} for chaining
* @api public
*/
res.contentType =
res.type = function(type){
return this.set('Content-Type', ~type.indexOf('/')
? type
: mime.lookup(type));
};
/**
* Respond to the Acceptable formats using an `obj`
* of mime-type callbacks.
*
* This method uses `req.accepted`, an array of
* acceptable types ordered by their quality values.
* When "Accept" is not present the _first_ callback
* is invoked, otherwise the first match is used. When
* no match is performed the server responds with
* 406 "Not Acceptable".
*
* Content-Type is set for you, however if you choose
* you may alter this within the callback using `res.type()`
* or `res.set('Content-Type', ...)`.
*
* res.format({
* 'text/plain': function(){
* res.send('hey');
* },
*
* 'text/html': function(){
* res.send('<p>hey</p>');
* },
*
* 'appliation/json': function(){
* res.send({ message: 'hey' });
* }
* });
*
* In addition to canonicalized MIME types you may
* also use extnames mapped to these types:
*
* res.format({
* text: function(){
* res.send('hey');
* },
*
* html: function(){
* res.send('<p>hey</p>');
* },
*
* json: function(){
* res.send({ message: 'hey' });
* }
* });
*
* @param {Object} obj
* @return {ServerResponse} for chaining
* @api public
*/
res.format = function(obj){
var keys = Object.keys(obj)
, req = this.req
, next = req.next
, key = req.accepts(keys);
this.set('Vary', 'Accept');
if (key) {
this.set('Content-Type', normalizeType(key));
obj[key](req, this, next);
} else {
var err = new Error('Not Acceptable');
err.status = 406;
err.types = normalizeTypes(keys);
next(err);
}
return this;
};
/**
@@ -217,70 +349,49 @@ res.contentType = function(type){
*/
res.attachment = function(filename){
if (filename) this.contentType(filename);
this.header('Content-Disposition', filename
if (filename) this.type(extname(filename));
this.set('Content-Disposition', filename
? 'attachment; filename="' + basename(filename) + '"'
: 'attachment');
return this;
};
/**
* Transfer the file at the given `path`, with optional
* `filename` as an attachment and optional callback `fn(err)`,
* and optional `fn2(err)` which is invoked when an error has
* occurred after header has been sent.
* Set header `field` to `val`, or pass
* an object of of header fields.
*
* @param {String} path
* @param {String|Function} filename or fn
* @param {Function} fn
* @param {Function} fn2
* Examples:
*
* res.set('Accept', 'application/json');
* res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' });
*
* @param {String|Object} field
* @param {String} val
* @return {ServerResponse} for chaining
* @api public
*/
res.download = function(path, filename, fn, fn2){
var self = this;
// support callback as second arg
if ('function' == typeof filename) {
fn2 = fn;
fn = filename;
filename = null;
}
// transfer the file
this.attachment(filename || path).sendfile(path, function(err){
var sentHeader = self._header;
if (err) {
if (!sentHeader) self.removeHeader('Content-Disposition');
if (sentHeader) {
fn2 && fn2(err);
} else if (fn) {
fn(err);
} else {
self.req.next(err);
}
} else if (fn) {
fn();
res.set = function(field, val){
if (2 == arguments.length) {
this.setHeader(field, val);
} else {
for (var key in field) {
this.setHeader(key, field[key]);
}
});
}
return this;
};
/**
* Set or get response header `name` with optional `val`.
* Get value for header `field`.
*
* @param {String} name
* @param {String} val
* @param {String} field
* @return {String}
* @api public
*/
res.header = function(name, val){
if (val === undefined) {
return this.getHeader(name);
} else {
this.setHeader(name, val);
return val;
}
res.get = function(field){
return this.getHeader(field);
};
/**
@@ -288,23 +399,42 @@ res.header = function(name, val){
*
* @param {String} name
* @param {Object} options
* @param {ServerResponse} for chaining
* @api public
*/
res.clearCookie = function(name, options){
var opts = { expires: new Date(1) };
this.cookie(name, '', options
? utils.merge(options, opts)
var opts = { expires: new Date(1), path: '/' };
return this.cookie(name, '', options
? utils.merge(opts, options)
: opts);
};
/**
* Set a signed cookie with the given `name` and `val`.
* See `res.cookie()` for details.
*
* @param {String} name
* @param {String|Object} val
* @param {Object} options
* @api public
*/
res.signedCookie = function(name, val, options){
var secret = this.req.secret;
if (!secret) throw new Error('connect.cookieParser("secret") required for signed cookies');
if ('object' == typeof val) val = 'j:' + JSON.stringify(val);
val = utils.sign(val, secret);
return this.cookie(name, val, options);
};
/**
* Set cookie `name` to `val`, with the given `options`.
*
* Options:
*
* - `maxAge` max-age in milliseconds, converted to `expires`
* - `path` defaults to the "home" setting which is typically "/"
* - `path` defaults to "/"
*
* Examples:
*
@@ -315,148 +445,174 @@ res.clearCookie = function(name, options){
* res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
*
* @param {String} name
* @param {String} val
* @param {String|Object} val
* @param {Options} options
* @api public
*/
res.cookie = function(name, val, options){
options = options || {};
if ('object' == typeof val) val = 'j:' + JSON.stringify(val);
if ('maxAge' in options) options.expires = new Date(Date.now() + options.maxAge);
if (undefined === options.path) options.path = this.app.set('home');
if (null == options.path) options.path = '/';
var cookie = utils.serializeCookie(name, val, options);
this.header('Set-Cookie', cookie);
this.set('Set-Cookie', cookie);
return this;
};
/**
* Redirect to the given `url` with optional response `status`
* defauling to 302.
* defaulting to 302.
*
* The given `url` can also be the name of a mapped url, for
* example by default express supports "back" which redirects
* to the _Referrer_ or _Referer_ headers or the application's
* "home" setting. Express also supports "home" out of the box,
* which can be set via `app.set('home', '/blog');`, and defaults
* to '/'.
* to the _Referrer_ or _Referer_ headers or "/".
*
* Redirect Mapping:
*
* To extend the redirect mapping capabilities that Express provides,
* we may use the `app.redirect()` method:
*
* app.redirect('google', 'http://google.com');
*
* Now in a route we may call:
* Examples:
*
* res.redirect('google');
* res.redirect('/foo/bar');
* res.redirect('http://example.com');
* res.redirect(301, 'http://example.com');
* res.redirect('../login'); // /blog/post/1 -> /blog/login
*
* We may also map dynamic redirects:
* Mounting:
*
* app.redirect('comments', function(req, res){
* return '/post/' + req.params.id + '/comments';
* });
* When an application is mounted, and `res.redirect()`
* is given a path that does _not_ lead with "/". For
* example suppose a "blog" app is mounted at "/blog",
* the following redirect would result in "/blog/login":
*
* So now we may do the following, and the redirect will dynamically adjust to
* the context of the request. If we called this route with _GET /post/12_ our
* redirect _Location_ would be _/post/12/comments_.
* res.redirect('login');
*
* app.get('/post/:id', function(req, res){
* res.redirect('comments');
* });
* While the leading slash would result in a redirect to "/login":
*
* Unless an absolute `url` is given, the app's mount-point
* will be respected. For example if we redirect to `/posts`,
* and our app is mounted at `/blog` we will redirect to `/blog/posts`.
* res.redirect('/login');
*
* @param {String} url
* @param {Number} code
* @api public
*/
res.redirect = function(url, status){
res.redirect = function(url){
var app = this.app
, req = this.req
, base = app.set('home') || '/'
, status = status || 302
, head = 'HEAD' == req.method
, status = 302
, body;
// Setup redirect map
var map = {
back: req.header('Referrer', base)
, home: base
};
// allow status / url
if (2 == arguments.length) {
status = url;
url = arguments[1];
}
// Support custom redirect map
map.__proto__ = app.redirects;
// setup redirect map
var map = { back: req.get('Referrer') || '/' };
// Attempt mapped redirect
var mapped = 'function' == typeof map[url]
? map[url](req, this)
: map[url];
// perform redirect
url = map[url] || url;
// Perform redirect
url = mapped || url;
// Relative
// relative
if (!~url.indexOf('://')) {
// Respect mount-point
if (app.route) url = join(app.route, url);
var path = app.path();
// relative to path
if (0 == url.indexOf('./') || 0 == url.indexOf('..')) {
url = req.path + '/' + url;
// relative to mount-point
} else if ('/' != url[0]) {
url = path + '/' + url;
}
// Absolute
var host = req.headers.host
, tls = req.connection.encrypted;
url = 'http' + (tls ? 's' : '') + '://' + host + url;
var host = req.get('Host');
url = req.protocol + '://' + host + url;
}
// Support text/{plain,html} by default
if (req.accepts('html')) {
body = '<p>' + http.STATUS_CODES[status] + '. Redirecting to <a href="' + url + '">' + url + '</a></p>';
this.header('Content-Type', 'text/html');
} else {
body = http.STATUS_CODES[status] + '. Redirecting to ' + url;
this.header('Content-Type', 'text/plain');
}
this.format({
'text/plain': function(){
body = statusCodes[status] + '. Redirecting to ' + url;
},
'text/html': function(){
body = '<p>' + statusCodes[status] + '. Redirecting to <a href="' + url + '">' + url + '</a></p>';
}
})
// Respond
this.statusCode = status;
this.header('Location', url);
this.end(body);
this.set('Location', url);
this.end(head ? null : body);
};
/**
* Assign the view local variable `name` to `val` or return the
* local previously assigned to `name`.
* Render `view` with the given `options` and optional callback `fn`.
* When a callback function is given a response will _not_ be made
* automatically, otherwise a response of _200_ and _text/html_ is given.
*
* @param {String} name
* @param {Mixed} val
* @return {Mixed} val
* Options:
*
* - `status` Response status code (`res.statusCode`)
* - `charset` Set the charset (`res.charset`)
*
* Reserved locals:
*
* - `cache` boolean hinting to the engine it should cache
* - `filename` filename of the view being rendered
*
* @param {String} view
* @param {Object|Function} options or callback function
* @param {Function} fn
* @api public
*/
res.local = function(name, val){
this._locals = this._locals || {};
return undefined === val
? this._locals[name]
: this._locals[name] = val;
};
res.render = function(view, options, fn){
var self = this
, options = options || {}
, req = this.req
, app = req.app;
/**
* Assign several locals with the given `obj`,
* or return the locals.
*
* @param {Object} obj
* @return {Object|Undefined}
* @api public
*/
// support callback function as second arg
if ('function' == typeof options) {
fn = options, options = {};
}
res.locals =
res.helpers = function(obj){
if (obj) {
for (var key in obj) {
this.local(key, obj[key]);
function render() {
// merge res.locals
options.locals = self.locals;
// default callback to respond
fn = fn || function(err, str){
if (err) return req.next(err);
self.send(str);
};
// render
app.render(view, options, fn);
}
// invoke view callbacks
var callbacks = app.viewCallbacks
, pending = callbacks.length
, len = pending
, done;
if (len) {
for (var i = 0; i < len; ++i) {
callbacks[i](req, self, function(err){
if (done) return;
if (err) {
req.next(err);
done = true;
return;
}
--pending || render();
});
}
} else {
return this._locals;
render();
}
};
};
-53
Ver Arquivo
@@ -1,53 +0,0 @@
/*!
* Express - router - Collection
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* Expose `Collection`.
*/
module.exports = Collection;
/**
* Initialize a new route `Collection`
* with the given `router`.
*
* @param {Router} router
* @api private
*/
function Collection(router) {
Array.apply(this, arguments);
this.router = router;
}
/**
* Inherit from `Array.prototype`.
*/
Collection.prototype.__proto__ = Array.prototype;
/**
* Remove the routes in this collection.
*
* @return {Collection} of routes removed
* @api public
*/
Collection.prototype.remove = function(){
var router = this.router
, len = this.length
, ret = new Collection(this.router);
for (var i = 0; i < len; ++i) {
if (router.remove(this[i])) {
ret.push(this[i]);
}
}
return ret;
};
+94 -183
Ver Arquivo
@@ -1,4 +1,3 @@
/*!
* Express - Router
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
@@ -10,10 +9,9 @@
*/
var Route = require('./route')
, Collection = require('./collection')
, utils = require('../utils')
, parse = require('url').parse
, toArray = utils.toArray;
, debug = require('debug')('express:router')
, parse = require('url').parse;
/**
* Expose `Router` constructor.
@@ -28,20 +26,22 @@ exports = module.exports = Router;
var methods = exports.methods = require('./methods');
/**
* Initialize a new `Router` with the given `app`.
* Initialize a new `Router` with the given `options`.
*
* @param {express.HTTPServer} app
* @param {Object} options
* @api private
*/
function Router(app) {
function Router(options) {
options = options || {};
var self = this;
this.app = app;
this.routes = {};
this.map = {};
this.params = {};
this._params = [];
this.caseSensitive = options.caseSensitive;
this.strict = options.strict;
this.middleware = function(req, res, next){
this.middleware = function router(req, res, next){
self._dispatch(req, res, next);
};
}
@@ -79,95 +79,10 @@ Router.prototype.param = function(name, fn){
throw new Error('invalid param() call for ' + name + ', got ' + fn);
}
this.params[name] = fn;
(this.params[name] = this.params[name] || []).push(fn);
return this;
};
/**
* Remove the given `route`, returns
* a bool indicating if the route was present
* or not.
*
* @param {Route} route
* @return {Boolean}
* @api public
*/
Router.prototype.remove = function(route){
var routes = this.routes[route.method]
, len = routes.length;
for (var i = 0; i < len; ++i) {
if (route == routes[i]) {
routes.splice(i, 1);
return true;
}
}
};
/**
* Return routes with route paths matching `path`.
*
* @param {String} method
* @param {String} path
* @return {Collection}
* @api public
*/
Router.prototype.lookup = function(method, path){
return this.find(function(route){
return path == route.path
&& (route.method == method
|| method == 'all');
});
};
/**
* Return routes with regexps that match the given `url`.
*
* @param {String} method
* @param {String} url
* @return {Collection}
* @api public
*/
Router.prototype.match = function(method, url){
return this.find(function(route){
return route.match(url)
&& (route.method == method
|| method == 'all');
});
};
/**
* Find routes based on the return value of `fn`
* which is invoked once per route.
*
* @param {Function} fn
* @return {Collection}
* @api public
*/
Router.prototype.find = function(fn){
var len = methods.length
, ret = new Collection(this)
, method
, routes
, route;
for (var i = 0; i < len; ++i) {
method = methods[i];
routes = this.routes[method];
if (!routes) continue;
for (var j = 0, jlen = routes.length; j < jlen; ++j) {
route = routes[j];
if (fn(route)) ret.push(route);
}
}
return ret;
};
/**
* Route dispatcher aka the route "middleware".
*
@@ -181,25 +96,32 @@ Router.prototype._dispatch = function(req, res, next){
var params = this.params
, self = this;
debug('dispatching %s %s', req.method, req.url);
// route dispatch
(function pass(i){
var route
(function pass(i, err){
var paramCallbacks
, paramIndex = 0
, paramVal
, route
, keys
, key
, ret;
// match next route
function nextRoute() {
pass(req._route_index + 1);
function nextRoute(err) {
pass(req._route_index + 1, err);
}
// match route
req.route = route = self._match(req, i);
req.route = route = self.match(req, i);
// implied OPTIONS
if (!route && 'OPTIONS' == req.method) return self._options(req, res);
// no route
if (!route) return next();
if (!route) return next(err);
debug('matched %s %s', route.method, route.path);
// we have a route
// start at param 0
@@ -207,50 +129,58 @@ Router.prototype._dispatch = function(req, res, next){
keys = route.keys;
i = 0;
(function param(err) {
var key = keys[i++]
, val = key && req.params[key.name]
, fn = key && params[key.name]
, ret;
// param callbacks
function param(err) {
paramIndex = 0;
key = keys[i++];
paramVal = key && req.params[key.name];
paramCallbacks = key && params[key.name];
try {
if ('route' == err) {
nextRoute();
} else if (err) {
next(err);
} else if (fn && undefined !== val) {
fn(req, res, param, val);
i = 0;
callbacks(err);
} else if (paramCallbacks && undefined !== paramVal) {
paramCallback();
} else if (key) {
param();
} else {
i = 0;
middleware();
callbacks();
}
} catch (err) {
next(err);
}
})();
// invoke route middleware
function middleware(err) {
var fn = route.middleware[i++];
if ('route' == err) {
nextRoute();
} else if (err) {
next(err);
} else if (fn) {
fn(req, res, middleware);
} else {
done();
param(err);
}
};
// invoke middleware callback
function done() {
route.callback.call(self, req, res, function(err){
if (err) return next(err);
pass(req._route_index + 1);
});
param(err);
// single param callbacks
function paramCallback(err) {
var fn = paramCallbacks[paramIndex++];
if (err || !fn) return param(err);
fn(req, res, paramCallback, paramVal, key.name);
}
// invoke route callbacks
function callbacks(err) {
var fn = route.callbacks[i++];
try {
if ('route' == err) {
nextRoute();
} else if (err && fn) {
if (fn.length < 4) return callbacks(err);
fn(err, req, res, callbacks);
} else if (fn) {
fn(req, res, callbacks);
} else {
nextRoute(err);
}
} catch (err) {
callbacks(err);
}
}
})(0);
};
@@ -266,7 +196,7 @@ Router.prototype._dispatch = function(req, res, next){
Router.prototype._options = function(req, res){
var path = parse(req.url).pathname
, body = this._optionsFor(path).join(',');
res.send(body, { Allow: body });
res.set('Allow', body).send(body);
};
/**
@@ -280,7 +210,7 @@ Router.prototype._options = function(req, res){
Router.prototype._optionsFor = function(path){
var self = this;
return methods.filter(function(method){
var routes = self.routes[method];
var routes = self.map[method];
if (!routes || 'options' == method) return;
for (var i = 0, len = routes.length; i < len; ++i) {
if (routes[i].match(path)) return true;
@@ -292,7 +222,8 @@ Router.prototype._optionsFor = function(path){
/**
* Attempt to match a route for `req`
* starting from offset `i`.
* with optional starting index of `i`
* defaulting to 0.
*
* @param {IncomingMessage} req
* @param {Number} i
@@ -300,17 +231,25 @@ Router.prototype._optionsFor = function(path){
* @api private
*/
Router.prototype._match = function(req, i){
Router.prototype.match = function(req, i, head){
var method = req.method.toLowerCase()
, url = parse(req.url)
, path = url.pathname
, routes = this.routes
, captures
, route
, keys;
, routes = this.map
, i = i || 0
, route;
// pass HEAD to GET routes
if ('head' == method) method = 'get';
// HEAD support
// TODO: clean this up
if (!head && 'head' == method) {
// attempt lookup
route = this.match(req, i, true);
if (route) return route;
// default to GET as res.render() / res.send()
// etc support HEAD
method = 'get';
}
// routes for this method
if (routes = routes[method]) {
@@ -318,24 +257,7 @@ Router.prototype._match = function(req, i){
// matching routes
for (var len = routes.length; i < len; ++i) {
route = routes[i];
if (captures = route.match(path)) {
keys = route.keys;
route.params = [];
// params from capture groups
for (var j = 1, jlen = captures.length; j < jlen; ++j) {
var key = keys[j-1]
, val = 'string' == typeof captures[j]
? decodeURIComponent(captures[j])
: captures[j];
if (key) {
route.params[key.name] = val;
} else {
route.params.push(val);
}
}
// all done
if (route.match(path)) {
req._route_index = i;
return route;
}
@@ -344,41 +266,30 @@ Router.prototype._match = function(req, i){
};
/**
* Route `method`, `path`, and optional middleware
* to the callback `fn`.
* Route `method`, `path`, and one or more callbacks.
*
* @param {String} method
* @param {String} path
* @param {Function} ...
* @param {Function} fn
* @param {Function} callback...
* @return {Router} for chaining
* @api private
*/
Router.prototype._route = function(method, path, fn){
var app = this.app
, middleware = [];
Router.prototype.route = function(method, path, callbacks){
var method = method.toLowerCase()
, callbacks = utils.flatten([].slice.call(arguments, 2));
// slice middleware
if (arguments.length > 3) {
middleware = toArray(arguments, 2);
fn = middleware.pop();
middleware = utils.flatten(middleware);
}
// ensure path and callback are given
if (!path) throw new Error(method + 'route requires a path');
if (!fn) throw new Error(method + ' route ' + path + ' requires a callback');
// ensure path was given
if (!path) throw new Error('Router#' + method + '() requires a path');
// create the route
var route = new Route(method, path, fn, {
sensitive: app.enabled('case sensitive routes')
, strict: app.enabled('strict routing')
, middleware: middleware
debug('defined %s %s', method, path);
var route = new Route(method, path, callbacks, {
sensitive: this.caseSensitive
, strict: this.strict
});
// add it
(this.routes[method] = this.routes[method] || [])
.push(route);
(this.map[method] = this.map[method] || []).push(route);
return this;
};
+26 -60
Ver Arquivo
@@ -6,65 +6,31 @@
*/
/**
* Hypertext Transfer Protocol -- HTTP/1.1
* http://www.ietf.org/rfc/rfc2616.txt
* HTTP methods supported by node.
*/
var RFC2616 = ['OPTIONS', 'GET', 'POST', 'PUT', 'DELETE', 'TRACE', 'CONNECT'];
/**
* HTTP Extensions for Distributed Authoring -- WEBDAV
* http://www.ietf.org/rfc/rfc2518.txt
*/
var RFC2518 = ['PROPFIND', 'PROPPATCH', 'MKCOL', 'COPY', 'MOVE', 'LOCK', 'UNLOCK'];
/**
* Versioning Extensions to WebDAV
* http://www.ietf.org/rfc/rfc3253.txt
*/
var RFC3253 = ['VERSION-CONTROL', 'REPORT', 'CHECKOUT', 'CHECKIN', 'UNCHECKOUT', 'MKWORKSPACE', 'UPDATE', 'LABEL', 'MERGE', 'BASELINE-CONTROL', 'MKACTIVITY'];
/**
* Ordered Collections Protocol (WebDAV)
* http://www.ietf.org/rfc/rfc3648.txt
*/
var RFC3648 = ['ORDERPATCH'];
/**
* Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol
* http://www.ietf.org/rfc/rfc3744.txt
*/
var RFC3744 = ['ACL'];
/**
* Web Distributed Authoring and Versioning (WebDAV) SEARCH
* http://www.ietf.org/rfc/rfc5323.txt
*/
var RFC5323 = ['SEARCH'];
/**
* PATCH Method for HTTP
* http://www.ietf.org/rfc/rfc5789.txt
*/
var RFC5789 = ['PATCH'];
/**
* Expose the methods.
*/
module.exports = [].concat(
RFC2616
, RFC2518
, RFC3253
, RFC3648
, RFC3744
, RFC5323
, RFC5789).map(function(method){
return method.toLowerCase();
});
module.exports = [
'get'
, 'post'
, 'put'
, 'head'
, 'delete'
, 'options'
, 'trace'
, 'copy'
, 'lock'
, 'mkcol'
, 'move'
, 'propfind'
, 'proppatch'
, 'unlock'
, 'report'
, 'mkactivity'
, 'checkout'
, 'merge'
, 'm-search'
, 'notify'
, 'subscribe'
, 'unsubscribe'
, 'patch'
];
+35 -47
Ver Arquivo
@@ -5,6 +5,12 @@
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../utils');
/**
* Expose `Route`.
*/
@@ -13,78 +19,60 @@ module.exports = Route;
/**
* Initialize `Route` with the given HTTP `method`, `path`,
* and callback `fn` and `options`.
* and an array of `callbacks` and `options`.
*
* Options:
*
* - `sensitive` enable case-sensitive routes
* - `strict` enable strict matching for trailing slashes
* - `middleware` array of middleware
*
* @param {String} method
* @param {String} path
* @param {Function} fn
* @param {Array} callbacks
* @param {Object} options.
* @api private
*/
function Route(method, path, fn, options) {
function Route(method, path, callbacks, options) {
options = options || {};
this.callback = fn;
this.path = path;
this.method = method;
this.middleware = options.middleware;
this.regexp = normalize(path
this.callbacks = callbacks;
this.regexp = utils.pathRegexp(path
, this.keys = []
, options.sensitive
, options.strict);
}
/**
* Check if this route matches `path` and return captures made.
* Check if this route matches `path`, if so
* populate `.params`.
*
* @param {String} path
* @return {Array}
* @return {Boolean}
* @api private
*/
Route.prototype.match = function(path){
return this.regexp.exec(path);
var keys = this.keys
, params = this.params = []
, m = this.regexp.exec(path);
if (!m) return false;
for (var i = 1, len = m.length; i < len; ++i) {
var key = keys[i - 1];
var val = 'string' == typeof m[i]
? decodeURIComponent(m[i])
: m[i];
if (key) {
params[key.name] = val;
} else {
params.push(val);
}
}
return true;
};
/**
* Normalize the given path string,
* returning a regular expression.
*
* An empty array should be passed,
* which will contain the placeholder
* key names. For example "/user/:id" will
* then contain ["id"].
*
* @param {String|RegExp} path
* @param {Array} keys
* @param {Boolean} sensitive
* @param {Boolean} strict
* @return {RegExp}
* @api private
*/
function normalize(path, keys, sensitive, strict) {
if (path instanceof RegExp) return path;
path = path
.concat(strict ? '' : '/?')
.replace(/\/\(/g, '(?:/')
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional){
keys.push({ name: key, optional: !! optional });
slash = slash || '';
return ''
+ (optional ? '' : slash)
+ '(?:'
+ (optional ? slash : '')
+ (format || '') + (capture || '([^/]+?)') + ')'
+ (optional || '');
})
.replace(/([\/.])/g, '\\$1')
.replace(/\*/g, '(.+)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
}
+189 -74
Ver Arquivo
@@ -1,33 +1,27 @@
/*!
* Express - Utils
* Express - utils
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* Merge object `b` with `a` giving precedence to
* values in object `a`.
* Module dependencies.
*/
var mime = require('mime');
/**
* Check if `path` looks absolute.
*
* @param {Object} a
* @param {Object} b
* @return {Object} a
* @param {String} path
* @return {Boolean}
* @api private
*/
exports.union = function(a, b){
if (a && b) {
var keys = Object.keys(b)
, len = keys.length
, key;
for (var i = 0; i < len; ++i) {
key = keys[i];
if (!a.hasOwnProperty(key)) {
a[key] = b[key];
}
}
}
return a;
exports.isAbsolute = function(path){
if ('/' == path[0]) return true;
if (':' == path[1] && '\\' == path[2]) return true;
};
/**
@@ -52,26 +46,158 @@ exports.flatten = function(arr, ret){
};
/**
* Parse mini markdown implementation.
* The following conversions are supported,
* primarily for the "flash" middleware:
* Normalize the given `type`, for example "html" becomes "text/html".
*
* _foo_ or *foo* become <em>foo</em>
* __foo__ or **foo** become <strong>foo</strong>
* [A](B) becomes <a href="B">A</a>
* @param {String} type
* @return {String}
* @api private
*/
exports.normalizeType = function(type){
return ~type.indexOf('/') ? type : mime.lookup(type);
};
/**
* Normalize `types`, for example "html" becomes "text/html".
*
* @param {Array} types
* @return {Array}
* @api private
*/
exports.normalizeTypes = function(types){
var ret = [];
for (var i = 0; i < types.length; ++i) {
ret.push(~types[i].indexOf('/')
? types[i]
: mime.lookup(types[i]));
}
return ret;
};
/**
* Return the acceptable type in `types`, if any.
*
* @param {Array} types
* @param {String} str
* @return {String}
* @api private
*/
exports.miniMarkdown = function(str){
return String(str)
.replace(/(__|\*\*)(.*?)\1/g, '<strong>$2</strong>')
.replace(/(_|\*)(.*?)\1/g, '<em>$2</em>')
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
exports.acceptsArray = function(types, str){
// accept anything when Accept is not present
if (!str) return types[0];
// parse
var accepted = exports.parseAccept(str)
, normalized = exports.normalizeTypes(types)
, len = accepted.length;
for (var i = 0; i < len; ++i) {
for (var j = 0, jlen = types.length; j < jlen; ++j) {
if (exports.accept(normalized[j].split('/'), accepted[i])) {
return types[j];
}
}
}
};
/**
* Check if `type(s)` are acceptable based on
* the given `str`.
*
* @param {String|Array} type(s)
* @param {String} str
* @return {Boolean|String}
* @api private
*/
exports.accepts = function(type, str){
if ('string' == typeof type) type = type.split(/ *, */);
return exports.acceptsArray(type, str);
};
/**
* Check if `type` array is acceptable for `other`.
*
* @param {Array} type
* @param {Object} other
* @return {Boolean}
* @api private
*/
exports.accept = function(type, other){
return (type[0] == other.type || '*' == other.type)
&& (type[1] == other.subtype || '*' == other.subtype);
};
/**
* Parse accept `str`, returning
* an array objects containing
* `.type` and `.subtype` along
* with the values provided by
* `parseQuality()`.
*
* @param {Type} name
* @return {Type}
* @api private
*/
exports.parseAccept = function(str){
return exports
.parseQuality(str)
.map(function(obj){
var parts = obj.value.split('/');
obj.type = parts[0];
obj.subtype = parts[1];
return obj;
});
};
/**
* Parse quality `str`, returning an
* array of objects with `.value` and
* `.quality`.
*
* @param {Type} name
* @return {Type}
* @api private
*/
exports.parseQuality = function(str){
return str
.split(/ *, */)
.map(quality)
.filter(function(obj){
return obj.quality;
})
.sort(function(a, b){
return b.quality - a.quality;
});
};
/**
* Parse quality `str` returning an
* object with `.value` and `.quality`.
*
* @param {String} str
* @return {Object}
* @api private
*/
function quality(str) {
var parts = str.split(/ *; */)
, val = parts[0];
var q = parts[1]
? parseFloat(parts[1].split(/ *= */)[1])
: 1;
return { value: val, quality: q };
}
/**
* Escape special characters in the given string of html.
*
@@ -89,51 +215,40 @@ exports.escape = function(html) {
};
/**
* Parse "Range" header `str` relative to the given file `size`.
* Normalize the given path string,
* returning a regular expression.
*
* @param {Number} size
* @param {String} str
* @return {Array}
* An empty array should be passed,
* which will contain the placeholder
* key names. For example "/user/:id" will
* then contain ["id"].
*
* @param {String|RegExp|Array} path
* @param {Array} keys
* @param {Boolean} sensitive
* @param {Boolean} strict
* @return {RegExp}
* @api private
*/
exports.parseRange = function(size, str){
var valid = true;
var arr = str.substr(6).split(',').map(function(range){
var range = range.split('-')
, start = parseInt(range[0], 10)
, end = parseInt(range[1], 10);
// -500
if (isNaN(start)) {
start = size - end;
end = size - 1;
// 500-
} else if (isNaN(end)) {
end = size - 1;
}
// Invalid
if (isNaN(start) || isNaN(end) || start > end) valid = false;
return { start: start, end: end };
});
return valid ? arr : undefined;
};
/**
* Fast alternative to `Array.prototype.slice.call()`.
*
* @param {Arguments} args
* @param {Number} n
* @return {Array}
* @api public
*/
exports.toArray = function(args, i){
var arr = []
, len = args.length
, i = i || 0;
for (; i < len; ++i) arr.push(args[i]);
return arr;
};
exports.pathRegexp = function(path, keys, sensitive, strict) {
if (path instanceof RegExp) return path;
if (path instanceof Array)
path = '(' + path.join('|') + ')';
path = path
.concat(strict ? '' : '/?')
.replace(/\/\(/g, '(?:/')
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional){
keys.push({ name: key, optional: !! optional });
slash = slash || '';
return ''
+ (optional ? '' : slash)
+ '(?:'
+ (optional ? slash : '')
+ (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')'
+ (optional || '');
})
.replace(/([\/.])/g, '\\$1')
.replace(/\*/g, '(.*)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
}
+51 -429
Ver Arquivo
@@ -1,6 +1,5 @@
/*!
* Express - view
* Express - View
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
@@ -10,450 +9,73 @@
*/
var path = require('path')
, extname = path.extname
, utils = require('./utils')
, dirname = path.dirname
, basename = path.basename
, utils = require('connect').utils
, View = require('./view/view')
, partial = require('./view/partial')
, union = require('./utils').union
, merge = utils.merge
, http = require('http')
, res = http.ServerResponse.prototype;
, extname = path.extname
, exists = path.existsSync
, join = path.join;
/**
* Expose constructors.
* Expose `View`.
*/
exports = module.exports = View;
module.exports = View;
/**
* Export template engine registrar.
*/
exports.register = View.register;
/**
* Lookup and compile `view` with cache support by supplying
* both the `cache` object and `cid` string,
* followed by `options` passed to `exports.lookup()`.
* Initialize a new `View` with the given `name`.
*
* @param {String} view
* @param {Object} cache
* @param {Object} cid
* Options:
*
* - `defaultEngine` the default template engine name
* - `engines` template engine require() cache
* - `root` root path for view lookup
*
* @param {String} name
* @param {Object} options
* @return {View}
* @api private
*/
exports.compile = function(view, cache, cid, options){
if (cache && cid && cache[cid]) return cache[cid];
// lookup
view = exports.lookup(view, options);
// hints
if (!view.exists) {
if (options.hint) hintAtViewPaths(view.original, options);
var err = new Error('failed to locate view "' + view.original.view + '"');
err.view = view.original;
throw err;
}
// compile
options.filename = view.path;
view.fn = view.templateEngine.compile(view.contents, options);
cache[cid] = view;
return view;
};
/**
* Lookup `view`, returning an instanceof `View`.
*
* Options:
*
* - `root` root directory path
* - `defaultEngine` default template engine
* - `parentView` parent `View` object
* - `cache` cache object
* - `cacheid` optional cache id
*
* Lookup:
*
* - partial `_<name>`
* - any `<name>/index`
* - non-layout `../<name>/index`
* - any `<root>/<name>`
* - partial `<root>/_<name>`
*
* @param {String} view
* @param {Object} options
* @return {View}
* @api private
*/
exports.lookup = function(view, options){
var orig = view = new View(view, options)
, partial = options.isPartial
, layout = options.isLayout;
// Try _ prefix ex: ./views/_<name>.jade
// taking precedence over the direct path
if (partial) {
view = new View(orig.prefixPath, options);
if (!view.exists) view = orig;
}
// Try index ex: ./views/user/index.jade
if (!layout && !view.exists) view = new View(orig.indexPath, options);
// Try ../<name>/index ex: ../user/index.jade
// when calling partial('user') within the same dir
if (!layout && !view.exists) view = new View(orig.upIndexPath, options);
// Try root ex: <root>/user.jade
if (!view.exists) view = new View(orig.rootPath, options);
// Try root _ prefix ex: <root>/_user.jade
if (!view.exists && partial) view = new View(view.prefixPath, options);
view.original = orig;
return view;
};
/**
* Partial render helper.
*
* @api private
*/
function renderPartial(res, view, options, parentLocals, parent){
var collection, object, locals;
if (options) {
// collection
if (options.collection) {
collection = options.collection;
delete options.collection;
} else if ('length' in options) {
collection = options;
options = {};
}
// locals
if (options.locals) {
locals = options.locals;
delete options.locals;
}
// object
if ('Object' != options.constructor.name) {
object = options;
options = {};
} else if (undefined != options.object) {
object = options.object;
delete options.object;
}
} else {
options = {};
}
// Inherit locals from parent
union(options, parentLocals);
// Merge locals
if (locals) merge(options, locals);
// Partials dont need layouts
options.isPartial = true;
options.layout = false;
// Deduce name from view path
var name = options.as || partial.resolveObjectName(view);
// Render partial
function render(){
if (object) {
if ('string' == typeof name) {
options[name] = object;
} else if (name === global) {
merge(options, object);
} else {
options.scope = object;
}
}
return res.render(view, options, null, parent, true);
}
// Collection support
if (collection) {
var len = collection.length
, buf = ''
, keys
, key
, val;
options.collectionLength = len;
if ('number' == typeof len || Array.isArray(collection)) {
for (var i = 0; i < len; ++i) {
val = collection[i];
options.firstInCollection = i == 0;
options.indexInCollection = i;
options.lastInCollection = i == len - 1;
object = val;
buf += render();
}
} else {
keys = Object.keys(collection);
len = keys.length;
options.collectionLength = len;
options.collectionKeys = keys;
for (var i = 0; i < len; ++i) {
key = keys[i];
val = collection[key];
options.keyInCollection = key;
options.firstInCollection = i == 0;
options.indexInCollection = i;
options.lastInCollection = i == len - 1;
object = val;
buf += render();
}
}
return buf;
} else {
return render();
}
};
/**
* Render `view` partial with the given `options`. Optionally a
* callback `fn(err, str)` may be passed instead of writing to
* the socket.
*
* Options:
*
* - `object` Single object with name derived from the view (unless `as` is present)
*
* - `as` Variable name for each `collection` value, defaults to the view name.
* * as: 'something' will add the `something` local variable
* * as: this will use the collection value as the template context
* * as: global will merge the collection value's properties with `locals`
*
* - `collection` Array of objects, the name is derived from the view name itself.
* For example _video.html_ will have a object _video_ available to it.
*
* @param {String} view
* @param {Object|Array|Function} options, collection, callback, or object
* @param {Function} fn
* @return {String}
* @api public
*/
res.partial = function(view, options, fn){
var app = this.app
, options = options || {}
, viewEngine = app.set('view engine')
, parent = {};
// accept callback as second argument
if ('function' == typeof options) {
fn = options;
options = {};
}
// root "views" option
parent.dirname = app.set('views') || process.cwd() + '/views';
// utilize "view engine" option
if (viewEngine) parent.engine = viewEngine;
// render the partial
try {
var str = renderPartial(this, view, options, null, parent);
} catch (err) {
if (fn) {
fn(err);
} else {
this.req.next(err);
}
return;
}
// callback or transfer
if (fn) {
fn(null, str);
} else {
this.send(str);
}
};
/**
* Render `view` with the given `options` and optional callback `fn`.
* When a callback function is given a response will _not_ be made
* automatically, however otherwise a response of _200_ and _text/html_ is given.
*
* Options:
*
* - `scope` Template evaluation context (the value of `this`)
* - `debug` Output debugging information
* - `status` Response status code
*
* @param {String} view
* @param {Object|Function} options or callback function
* @param {Function} fn
* @api public
*/
res.render = function(view, opts, fn, parent, sub){
// support callback function as second arg
if ('function' == typeof opts) {
fn = opts, opts = null;
}
try {
return this._render(view, opts, fn, parent, sub);
} catch (err) {
// callback given
if (fn) {
fn(err);
// unwind to root call to prevent multiple callbacks
} else if (sub) {
throw err;
// root template, next(err)
} else {
this.req.next(err);
}
}
};
// private render()
res._render = function(view, opts, fn, parent, sub){
var options = {}
, self = this
, app = this.app
, helpers = app._locals
, dynamicHelpers = app.dynamicViewHelpers
, viewOptions = app.set('view options')
, root = app.set('views') || process.cwd() + '/views';
// cache id
var cid = app.enabled('view cache')
? view + (parent ? ':' + parent.path : '')
: false;
// merge "view options"
if (viewOptions) merge(options, viewOptions);
// merge res._locals
if (this._locals) merge(options, this._locals);
// merge render() options
if (opts) merge(options, opts);
// merge render() .locals
if (opts && opts.locals) merge(options, opts.locals);
// status support
if (options.status) this.statusCode = options.status;
// capture attempts
options.attempts = [];
var partial = options.isPartial
, layout = options.layout;
// Layout support
if (true === layout || undefined === layout) {
layout = 'layout';
}
// Default execution scope to a plain object
options.scope = options.scope || {};
// Populate view
options.parentView = parent;
// "views" setting
options.root = root;
// "view engine" setting
options.defaultEngine = app.set('view engine');
// charset option
if (options.charset) this.charset = options.charset;
// Dynamic helper support
if (false !== options.dynamicHelpers) {
// cache
if (!this.__dynamicHelpers) {
this.__dynamicHelpers = {};
for (var key in dynamicHelpers) {
this.__dynamicHelpers[key] = dynamicHelpers[key].call(
this.app
, this.req
, this);
}
}
// apply
merge(options, this.__dynamicHelpers);
}
// Merge view helpers
union(options, helpers);
// Always expose partial() as a local
options.partial = function(path, opts){
return renderPartial(self, path, opts, options, view);
};
// View lookup
options.hint = app.enabled('hints');
view = exports.compile(view, app.cache, cid, options);
// layout helper
options.layout = function(path){
layout = path;
};
// render
var str = view.fn.call(options.scope, options);
// layout expected
if (layout) {
options.isLayout = true;
options.layout = false;
options.body = str;
this.render(layout, options, fn, view, true);
// partial return
} else if (partial) {
return str;
// render complete, and
// callback given
} else if (fn) {
fn(null, str);
// respond
} else {
this.send(str);
}
function View(name, options) {
options = options || {};
this.name = name;
this.root = options.root;
var engines = options.engines;
this.defaultEngine = options.defaultEngine;
var ext = this.ext = extname(name);
if (!ext) name += (ext = this.ext = '.' + this.defaultEngine);
this.engine = engines[ext] || (engines[ext] = require(ext.slice(1)).__express);
this.path = this.lookup(name);
}
/**
* Hint at view path resolution, outputting the
* paths that Express has tried.
* Lookup view by the given `path`
*
* @param {String} path
* @return {String}
* @api private
*/
function hintAtViewPaths(view, options) {
console.error();
console.error('failed to locate view "' + view.view + '", tried:');
options.attempts.forEach(function(path){
console.error(' - %s', path);
});
console.error();
}
View.prototype.lookup = function(path){
var ext = this.ext;
// <path>.<engine>
if (!utils.isAbsolute(path)) path = join(this.root, path);
if (exists(path)) return path;
// <path>/index.<engine>
path = join(dirname(path), basename(path, ext), 'index' + ext);
if (exists(path)) return path;
};
/**
* Render with the given `options` and callback `fn(err, str)`.
*
* @param {Object} options
* @param {Function} fn
* @api private
*/
View.prototype.render = function(options, fn){
this.engine(this.path, options, fn);
};
-40
Ver Arquivo
@@ -1,40 +0,0 @@
/*!
* Express - view - Partial
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* Memory cache.
*/
var cache = {};
/**
* Resolve partial object name from the view path.
*
* Examples:
*
* "user.ejs" becomes "user"
* "forum thread.ejs" becomes "forumThread"
* "forum/thread/post.ejs" becomes "post"
* "blog-post.ejs" becomes "blogPost"
*
* @return {String}
* @api private
*/
exports.resolveObjectName = function(view){
return cache[view] || (cache[view] = view
.split('/')
.slice(-1)[0]
.split('.')[0]
.replace(/^_/, '')
.replace(/[^a-zA-Z0-9 ]+/g, ' ')
.split(/ +/).map(function(word, i){
return i
? word[0].toUpperCase() + word.substr(1)
: word;
}).join(''));
};
-209
Ver Arquivo
@@ -1,209 +0,0 @@
/*!
* Express - View
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var path = require('path')
, extname = path.extname
, dirname = path.dirname
, basename = path.basename
, fs = require('fs')
, stat = fs.statSync;
/**
* Expose `View`.
*/
exports = module.exports = View;
/**
* Require cache.
*/
var cache = {};
/**
* Initialize a new `View` with the given `view` path and `options`.
*
* @param {String} view
* @param {Object} options
* @api private
*/
function View(view, options) {
options = options || {};
this.view = view;
this.root = options.root;
this.relative = false !== options.relative;
this.defaultEngine = options.defaultEngine;
this.parent = options.parentView;
this.basename = basename(view);
this.engine = this.resolveEngine();
this.extension = '.' + this.engine;
this.name = this.basename.replace(this.extension, '');
this.path = this.resolvePath();
this.dirname = dirname(this.path);
if (options.attempts) {
if (!~options.attempts.indexOf(this.path))
options.attempts.push(this.path);
}
};
/**
* Check if the view path exists.
*
* @return {Boolean}
* @api public
*/
View.prototype.__defineGetter__('exists', function(){
try {
stat(this.path);
return true;
} catch (err) {
return false;
}
});
/**
* Resolve view engine.
*
* @return {String}
* @api private
*/
View.prototype.resolveEngine = function(){
// Explicit
if (~this.basename.indexOf('.')) return extname(this.basename).substr(1);
// Inherit from parent
if (this.parent) return this.parent.engine;
// Default
return this.defaultEngine;
};
/**
* Resolve view path.
*
* @return {String}
* @api private
*/
View.prototype.resolvePath = function(){
var path = this.view;
// Implicit engine
if (!~this.basename.indexOf('.')) path += this.extension;
// Absolute
if ('/' == path[0]) return path;
// Relative to parent
if (this.relative && this.parent) return this.parent.dirname + '/' + path;
// Relative to root
return this.root
? this.root + '/' + path
: path;
};
/**
* Get view contents. This is a one-time hit, so we
* can afford to be sync.
*
* @return {String}
* @api public
*/
View.prototype.__defineGetter__('contents', function(){
return fs.readFileSync(this.path, 'utf8');
});
/**
* Get template engine api, cache exports to reduce
* require() calls.
*
* @return {Object}
* @api public
*/
View.prototype.__defineGetter__('templateEngine', function(){
var ext = this.extension;
return cache[ext] || (cache[ext] = require(this.engine));
});
/**
* Return root path alternative.
*
* @return {String}
* @api public
*/
View.prototype.__defineGetter__('rootPath', function(){
this.relative = false;
return this.resolvePath();
});
/**
* Return index path alternative.
*
* @return {String}
* @api public
*/
View.prototype.__defineGetter__('indexPath', function(){
return this.dirname
+ '/' + this.basename.replace(this.extension, '')
+ '/index' + this.extension;
});
/**
* Return ../<name>/index path alternative.
*
* @return {String}
* @api public
*/
View.prototype.__defineGetter__('upIndexPath', function(){
return this.dirname + '/../' + this.name + '/index' + this.extension;
});
/**
* Return _ prefix path alternative
*
* @return {String}
* @api public
*/
View.prototype.__defineGetter__('prefixPath', function(){
return this.dirname + '/_' + this.basename;
});
/**
* Register the given template engine `exports`
* as `ext`. For example we may wish to map ".html"
* files to jade:
*
* app.register('.html', require('jade'));
*
* or
*
* app.register('html', require('jade'));
*
* This is also useful for libraries that may not
* match extensions correctly. For example my haml.js
* library is installed from npm as "hamljs" so instead
* of layout.hamljs, we can register the engine as ".haml":
*
* app.register('.haml', require('haml-js'));
*
* @param {String} ext
* @param {Object} obj
* @api public
*/
exports.register = function(ext, exports) {
if ('.' != ext[0]) ext = '.' + ext;
cache[ext] = exports;
};

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais