Too many changes to show.
To preserve performance only 1000 of 1000+ files are displayed.
1 | +MIT License | ||
2 | + | ||
3 | +Copyright (c) 2017 Jayde-Im | ||
4 | + | ||
5 | +Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | +of this software and associated documentation files (the "Software"), to deal | ||
7 | +in the Software without restriction, including without limitation the rights | ||
8 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | +copies of the Software, and to permit persons to whom the Software is | ||
10 | +furnished to do so, subject to the following conditions: | ||
11 | + | ||
12 | +The above copyright notice and this permission notice shall be included in all | ||
13 | +copies or substantial portions of the Software. | ||
14 | + | ||
15 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
21 | +SOFTWARE. |
1 | + ,'''''', | ||
2 | + '''''''''''''' | ||
3 | + ''''' '''''''''''. | ||
4 | + '''' '''''''''''' | ||
5 | + '''' ;' '''', | ||
6 | + ''': :''' | ||
7 | + '':. `.;' | ||
8 | + ''''''''; ,'''''''' | ||
9 | + '''''''''''''; .''''''''''''', | ||
10 | + ,''''': '''''''' ,''''''' .'''''' | ||
11 | + '''', ,''''';'''''' '''', | ||
12 | + :'''' `'''''''; ,'''' | ||
13 | + :'''' ''''''' ,'''' | ||
14 | + ::::` ;::::::::::` ::::. | ||
15 | + ,;;;;;. .;;;;;;; ;;;;;;;: ;;;;;; | ||
16 | + ;;;;;;;;;;;;;; :;;;;;;;;;;;;;: | ||
17 | + ;;;;;;;;; :;;;;;;;;` GOORM IDE | ||
18 | + | ||
19 | + | ||
20 | +README | ||
21 | + | ||
22 | +기본적으로 개인별 포트는 3개가 주어집니다. 포트는 생성시기마다 다르게 주어질 수 있으므로, 다음과 같이 사용하시기 바랍니다. | ||
23 | + | ||
24 | +Node.js에서 실행하는 기본포트는 아래 변수를 통해 자동으로 연결됩니다. | ||
25 | +process.env.PORT | ||
26 | + | ||
27 | +사용 예제) | ||
28 | +var app = express(); | ||
29 | +var port = process.env.PORT || 3000; | ||
30 | +http.createServer(app).listen(port, function(){ | ||
31 | + console.log("Express server listening on port " + port); | ||
32 | +}); | ||
33 | + | ||
34 | +추가적인 PORT 필요시 아래 변수를 사용할 수 있습니다. | ||
35 | +process.env.PORT2 | ||
36 | +process.env.PORT3 |
1 | +# nodejs-todo-list | ||
2 | +Simple to-do Node.js web application using Express and jQuery. | ||
3 | + | ||
4 | +This is a sample project for lecture, **[TODO 앱을 직접 만들면서 배우는 node.js / express / bootstrap / jquery](http://edu.goorm.io/lecture/bGVjX3pOZmhrXzE0NzMzMjIyOTMzODI=)** in [goormEDU](http://edu.goorm.io/index) | ||
5 | + | ||
6 | + | ||
7 | + | ||
8 | +## How to start | ||
9 | + | ||
10 | +0. Install [Node.js](https://nodejs.org/en/): | ||
11 | + | ||
12 | +- Binaries, installers, and source tarballs are available at <https://nodejs.org/en/download/>. | ||
13 | +- Install suitable version for your platform. | ||
14 | + | ||
15 | +1. Download the project: | ||
16 | + | ||
17 | +- Download ZIP | ||
18 | +or | ||
19 | +- Clone the repo: | ||
20 | +```console | ||
21 | +$ git clone https://github.com/Jayde-Im/nodejs-todo-list.git | ||
22 | +``` | ||
23 | + | ||
24 | +2. Go to project directory and install dependencies: | ||
25 | + | ||
26 | +```console | ||
27 | +$ cd nodejs-todo-list | ||
28 | +``` | ||
29 | +```console | ||
30 | +$ npm install | ||
31 | +``` | ||
32 | + | ||
33 | +3. Run the application: | ||
34 | + | ||
35 | +```console | ||
36 | +$ npm start | ||
37 | +``` | ||
38 | + | ||
39 | + | ||
40 | +4. Open a browser and go to `localhost:3000`. | ||
41 | + | ||
42 | + | ||
43 | + | ||
44 | + | ||
45 | + | ||
46 | +## Report a bug | ||
47 | + | ||
48 | +If you find bugs or have any questions, [open a new issue](https://github.com/Jayde-Im/nodejs-todo-list/issues), please. |
1 | + ,'''''', | ||
2 | + '''''''''''''' | ||
3 | + ''''' '''''''''''. | ||
4 | + '''' '''''''''''' | ||
5 | + '''' ;' '''', | ||
6 | + ''': :''' | ||
7 | + '':. `.;' | ||
8 | + ''''''''; ,'''''''' | ||
9 | + '''''''''''''; .''''''''''''', | ||
10 | + ,''''': '''''''' ,''''''' .'''''' | ||
11 | + '''', ,''''';'''''' '''', | ||
12 | + :'''' `'''''''; ,'''' | ||
13 | + :'''' ''''''' ,'''' | ||
14 | + ::::` ;::::::::::` ::::. | ||
15 | + ,;;;;;. .;;;;;;; ;;;;;;;: ;;;;;; | ||
16 | + ;;;;;;;;;;;;;; :;;;;;;;;;;;;;: | ||
17 | + ;;;;;;;;; :;;;;;;;;` GOORM IDE | ||
18 | + | ||
19 | + | ||
20 | +README | ||
21 | + | ||
22 | +Basically we give you 3 ports of personal use. | ||
23 | +Since these port can be changed for its creating time, please use your port following the direction. | ||
24 | + | ||
25 | +Default port used by Node.js is automatically connected through this variable. | ||
26 | +process.env.PORT | ||
27 | + | ||
28 | +Examples) | ||
29 | +var app = express(); | ||
30 | +var port = process.env.PORT || 3000; | ||
31 | +http.createServer(app).listen(port, function(){ | ||
32 | +console.log("Express server listening on port " + port); | ||
33 | +}); | ||
34 | + | ||
35 | +If you need additional port, you can use other variables below. | ||
36 | +process.env.PORT2 | ||
37 | +process.env.PORT3 | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | + | ||
2 | +/** | ||
3 | + * Module dependencies. | ||
4 | + */ | ||
5 | + | ||
6 | +// 모듈 가져오기 | ||
7 | +var express = require('express') | ||
8 | + , routes = require('./routes') | ||
9 | + , todo = require('./routes/todo') | ||
10 | + , http = require('http') | ||
11 | + , path = require('path'); | ||
12 | + | ||
13 | +var app = express(); // 어플리케이션 생성 | ||
14 | +var port = 3000; // 어플리케이션 포트 | ||
15 | +var request = require('request'); | ||
16 | + | ||
17 | +// 어플리케이션 설정 | ||
18 | +app.configure(function(){ | ||
19 | + app.set('port', port); // 웹 서버 포트 | ||
20 | + app.set('views', __dirname + '/views'); // 템플릿 | ||
21 | + app.set('view engine', 'ejs'); // 템플릿 엔진 | ||
22 | + app.use(express.favicon()); // 파비콘 | ||
23 | + app.use(express.logger('dev')); // 로그 기록 | ||
24 | + app.use(express.bodyParser()); // 요청 본문 파싱 | ||
25 | + app.use(express.methodOverride()); // 구식 브라우저 메소드 지원 | ||
26 | + app.use(app.router); // 라우팅 | ||
27 | + | ||
28 | + // 정적 리소스 처리 | ||
29 | + app.use(require('stylus').middleware(__dirname + '/public')); | ||
30 | + app.use(express.static(path.join(__dirname, 'public'))); | ||
31 | +}); | ||
32 | + | ||
33 | +app.configure('development', function(){ // 개발 버전 | ||
34 | + app.use(express.errorHandler()); // 에러 메세지 | ||
35 | +}); | ||
36 | + | ||
37 | +// 라우팅 | ||
38 | +app.get('/', routes.index); | ||
39 | +app.get('/list', todo.list); | ||
40 | +app.post('/add', todo.add); | ||
41 | +app.post('/complete', todo.complete); | ||
42 | +app.post('/del', todo.del); | ||
43 | + | ||
44 | +// 서버 실행 | ||
45 | +http.createServer(app).listen(app.get('port'), function(){ | ||
46 | + console.log("Express server listening on port " + app.get('port')); | ||
47 | +}); |
1 | -var request = require('request'); | 1 | +/*var request = require('request'); |
2 | var optionParams = { | 2 | var optionParams = { |
3 | q:"염따", | 3 | q:"염따", |
4 | part:"snippet", | 4 | part:"snippet", |
... | @@ -6,7 +6,7 @@ var optionParams = { | ... | @@ -6,7 +6,7 @@ var optionParams = { |
6 | type:"video", | 6 | type:"video", |
7 | maxResult:2, | 7 | maxResult:2, |
8 | regionCode:"KR", | 8 | regionCode:"KR", |
9 | - videoDuration:"short" | 9 | + order:"viewCount" |
10 | }; | 10 | }; |
11 | optionParams.q = encodeURI(optionParams.q); | 11 | optionParams.q = encodeURI(optionParams.q); |
12 | var url = "https://www.googleapis.com/youtube/v3/search?"; | 12 | var url = "https://www.googleapis.com/youtube/v3/search?"; |
... | @@ -40,3 +40,39 @@ request(url, function(err,res,body){ | ... | @@ -40,3 +40,39 @@ request(url, function(err,res,body){ |
40 | }); | 40 | }); |
41 | video.pipe(fs.createWriteStream('justlikethat.mp4')); | 41 | video.pipe(fs.createWriteStream('justlikethat.mp4')); |
42 | }); | 42 | }); |
43 | +*/ | ||
44 | + | ||
45 | +var request=require('request'); | ||
46 | +var optionParams={ | ||
47 | + q:"코코몽", | ||
48 | + part:"snippet", | ||
49 | + key:"AIzaSyCgGa6aM7taXs4bajtYukbc_EQAKTLVTNc", | ||
50 | + type:"video", | ||
51 | + maxResults:10, | ||
52 | + regionCode:"KR", | ||
53 | + order:"viewCount" | ||
54 | + }; | ||
55 | + | ||
56 | +//한글을 검색어로 전달하기 위해선 url encoding 필요! | ||
57 | +optionParams.q=encodeURI(optionParams.q); | ||
58 | + | ||
59 | +var url="https://www.googleapis.com/youtube/v3/search?"; | ||
60 | +for(var option in optionParams){ | ||
61 | + url+=option+"="+optionParams[option]+"&"; | ||
62 | +} | ||
63 | + | ||
64 | +//url의마지막에 붙어있는 & 정리 | ||
65 | +url=url.substr(0, url.length-1); | ||
66 | + | ||
67 | +request(url, function(err, res, body){ | ||
68 | + // console.log(body) | ||
69 | + | ||
70 | + //json형식을 서버로 부터 받음 | ||
71 | + var data=JSON.parse(body).items; | ||
72 | + for(var content in data){ | ||
73 | + | ||
74 | + //youtube downloader에 videoId 넘기면 됨. | ||
75 | + console.log(data[content].snippet.title+" : "+data[content].id.videoId); | ||
76 | + | ||
77 | + } | ||
78 | +}); | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
1 | +#!/bin/sh | ||
2 | +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") | ||
3 | + | ||
4 | +case `uname` in | ||
5 | + *CYGWIN*) basedir=`cygpath -w "$basedir"`;; | ||
6 | +esac | ||
7 | + | ||
8 | +if [ -x "$basedir/node" ]; then | ||
9 | + "$basedir/node" "$basedir/../express/bin/express" "$@" | ||
10 | + ret=$? | ||
11 | +else | ||
12 | + node "$basedir/../express/bin/express" "$@" | ||
13 | + ret=$? | ||
14 | +fi | ||
15 | +exit $ret |
1 | +#!/bin/sh | ||
2 | +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") | ||
3 | + | ||
4 | +case `uname` in | ||
5 | + *CYGWIN*) basedir=`cygpath -w "$basedir"`;; | ||
6 | +esac | ||
7 | + | ||
8 | +if [ -x "$basedir/node" ]; then | ||
9 | + "$basedir/node" "$basedir/../stylus/bin/stylus" "$@" | ||
10 | + ret=$? | ||
11 | +else | ||
12 | + node "$basedir/../stylus/bin/stylus" "$@" | ||
13 | + ret=$? | ||
14 | +fi | ||
15 | +exit $ret |
... | @@ -21,7 +21,7 @@ | ... | @@ -21,7 +21,7 @@ |
21 | "_resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", | 21 | "_resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", |
22 | "_shasum": "90d0d54439da587cd7e843bfb7045f50bd22bdf1", | 22 | "_shasum": "90d0d54439da587cd7e843bfb7045f50bd22bdf1", |
23 | "_spec": "ajv@^6.5.5", | 23 | "_spec": "ajv@^6.5.5", |
24 | - "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\har-validator", | 24 | + "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\nodejs-todo-list-master\\node_modules\\har-validator", |
25 | "author": { | 25 | "author": { |
26 | "name": "Evgeny Poberezkin" | 26 | "name": "Evgeny Poberezkin" |
27 | }, | 27 | }, | ... | ... |
1 | +amdefine is released under two licenses: new BSD, and MIT. You may pick the | ||
2 | +license that best suits your development needs. The text of both licenses are | ||
3 | +provided below. | ||
4 | + | ||
5 | + | ||
6 | +The "New" BSD License: | ||
7 | +---------------------- | ||
8 | + | ||
9 | +Copyright (c) 2011-2016, The Dojo Foundation | ||
10 | +All rights reserved. | ||
11 | + | ||
12 | +Redistribution and use in source and binary forms, with or without | ||
13 | +modification, are permitted provided that the following conditions are met: | ||
14 | + | ||
15 | + * Redistributions of source code must retain the above copyright notice, this | ||
16 | + list of conditions and the following disclaimer. | ||
17 | + * Redistributions in binary form must reproduce the above copyright notice, | ||
18 | + this list of conditions and the following disclaimer in the documentation | ||
19 | + and/or other materials provided with the distribution. | ||
20 | + * Neither the name of the Dojo Foundation nor the names of its contributors | ||
21 | + may be used to endorse or promote products derived from this software | ||
22 | + without specific prior written permission. | ||
23 | + | ||
24 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
25 | +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
26 | +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
27 | +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | ||
28 | +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
29 | +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
30 | +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
31 | +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
32 | +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
33 | +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
34 | + | ||
35 | + | ||
36 | + | ||
37 | +MIT License | ||
38 | +----------- | ||
39 | + | ||
40 | +Copyright (c) 2011-2016, The Dojo Foundation | ||
41 | + | ||
42 | +Permission is hereby granted, free of charge, to any person obtaining a copy | ||
43 | +of this software and associated documentation files (the "Software"), to deal | ||
44 | +in the Software without restriction, including without limitation the rights | ||
45 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
46 | +copies of the Software, and to permit persons to whom the Software is | ||
47 | +furnished to do so, subject to the following conditions: | ||
48 | + | ||
49 | +The above copyright notice and this permission notice shall be included in | ||
50 | +all copies or substantial portions of the Software. | ||
51 | + | ||
52 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
53 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
54 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
55 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
56 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
57 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
58 | +THE SOFTWARE. |
1 | +# amdefine | ||
2 | + | ||
3 | +A module that can be used to implement AMD's define() in Node. This allows you | ||
4 | +to code to the AMD API and have the module work in node programs without | ||
5 | +requiring those other programs to use AMD. | ||
6 | + | ||
7 | +## Usage | ||
8 | + | ||
9 | +**1)** Update your package.json to indicate amdefine as a dependency: | ||
10 | + | ||
11 | +```javascript | ||
12 | + "dependencies": { | ||
13 | + "amdefine": ">=0.1.0" | ||
14 | + } | ||
15 | +``` | ||
16 | + | ||
17 | +Then run `npm install` to get amdefine into your project. | ||
18 | + | ||
19 | +**2)** At the top of each module that uses define(), place this code: | ||
20 | + | ||
21 | +```javascript | ||
22 | +if (typeof define !== 'function') { var define = require('amdefine')(module) } | ||
23 | +``` | ||
24 | + | ||
25 | +**Only use these snippets** when loading amdefine. If you preserve the basic structure, | ||
26 | +with the braces, it will be stripped out when using the [RequireJS optimizer](#optimizer). | ||
27 | + | ||
28 | +You can add spaces, line breaks and even require amdefine with a local path, but | ||
29 | +keep the rest of the structure to get the stripping behavior. | ||
30 | + | ||
31 | +As you may know, because `if` statements in JavaScript don't have their own scope, the var | ||
32 | +declaration in the above snippet is made whether the `if` expression is truthy or not. If | ||
33 | +RequireJS is loaded then the declaration is superfluous because `define` is already already | ||
34 | +declared in the same scope in RequireJS. Fortunately JavaScript handles multiple `var` | ||
35 | +declarations of the same variable in the same scope gracefully. | ||
36 | + | ||
37 | +If you want to deliver amdefine.js with your code rather than specifying it as a dependency | ||
38 | +with npm, then just download the latest release and refer to it using a relative path: | ||
39 | + | ||
40 | +[Latest Version](https://github.com/jrburke/amdefine/raw/latest/amdefine.js) | ||
41 | + | ||
42 | +### amdefine/intercept | ||
43 | + | ||
44 | +Consider this very experimental. | ||
45 | + | ||
46 | +Instead of pasting the piece of text for the amdefine setup of a `define` | ||
47 | +variable in each module you create or consume, you can use `amdefine/intercept` | ||
48 | +instead. It will automatically insert the above snippet in each .js file loaded | ||
49 | +by Node. | ||
50 | + | ||
51 | +**Warning**: you should only use this if you are creating an application that | ||
52 | +is consuming AMD style defined()'d modules that are distributed via npm and want | ||
53 | +to run that code in Node. | ||
54 | + | ||
55 | +For library code where you are not sure if it will be used by others in Node or | ||
56 | +in the browser, then explicitly depending on amdefine and placing the code | ||
57 | +snippet above is suggested path, instead of using `amdefine/intercept`. The | ||
58 | +intercept module affects all .js files loaded in the Node app, and it is | ||
59 | +inconsiderate to modify global state like that unless you are also controlling | ||
60 | +the top level app. | ||
61 | + | ||
62 | +#### Why distribute AMD-style modules via npm? | ||
63 | + | ||
64 | +npm has a lot of weaknesses for front-end use (installed layout is not great, | ||
65 | +should have better support for the `baseUrl + moduleID + '.js' style of loading, | ||
66 | +single file JS installs), but some people want a JS package manager and are | ||
67 | +willing to live with those constraints. If that is you, but still want to author | ||
68 | +in AMD style modules to get dynamic require([]), better direct source usage and | ||
69 | +powerful loader plugin support in the browser, then this tool can help. | ||
70 | + | ||
71 | +#### amdefine/intercept usage | ||
72 | + | ||
73 | +Just require it in your top level app module (for example index.js, server.js): | ||
74 | + | ||
75 | +```javascript | ||
76 | +require('amdefine/intercept'); | ||
77 | +``` | ||
78 | + | ||
79 | +The module does not return a value, so no need to assign the result to a local | ||
80 | +variable. | ||
81 | + | ||
82 | +Then just require() code as you normally would with Node's require(). Any .js | ||
83 | +loaded after the intercept require will have the amdefine check injected in | ||
84 | +the .js source as it is loaded. It does not modify the source on disk, just | ||
85 | +prepends some content to the text of the module as it is loaded by Node. | ||
86 | + | ||
87 | +#### How amdefine/intercept works | ||
88 | + | ||
89 | +It overrides the `Module._extensions['.js']` in Node to automatically prepend | ||
90 | +the amdefine snippet above. So, it will affect any .js file loaded by your | ||
91 | +app. | ||
92 | + | ||
93 | +## define() usage | ||
94 | + | ||
95 | +It is best if you use the anonymous forms of define() in your module: | ||
96 | + | ||
97 | +```javascript | ||
98 | +define(function (require) { | ||
99 | + var dependency = require('dependency'); | ||
100 | +}); | ||
101 | +``` | ||
102 | + | ||
103 | +or | ||
104 | + | ||
105 | +```javascript | ||
106 | +define(['dependency'], function (dependency) { | ||
107 | + | ||
108 | +}); | ||
109 | +``` | ||
110 | + | ||
111 | +## RequireJS optimizer integration. <a name="optimizer"></name> | ||
112 | + | ||
113 | +Version 1.0.3 of the [RequireJS optimizer](http://requirejs.org/docs/optimization.html) | ||
114 | +will have support for stripping the `if (typeof define !== 'function')` check | ||
115 | +mentioned above, so you can include this snippet for code that runs in the | ||
116 | +browser, but avoid taking the cost of the if() statement once the code is | ||
117 | +optimized for deployment. | ||
118 | + | ||
119 | +## Node 0.4 Support | ||
120 | + | ||
121 | +If you want to support Node 0.4, then add `require` as the second parameter to amdefine: | ||
122 | + | ||
123 | +```javascript | ||
124 | +//Only if you want Node 0.4. If using 0.5 or later, use the above snippet. | ||
125 | +if (typeof define !== 'function') { var define = require('amdefine')(module, require) } | ||
126 | +``` | ||
127 | + | ||
128 | +## Limitations | ||
129 | + | ||
130 | +### Synchronous vs Asynchronous | ||
131 | + | ||
132 | +amdefine creates a define() function that is callable by your code. It will | ||
133 | +execute and trace dependencies and call the factory function *synchronously*, | ||
134 | +to keep the behavior in line with Node's synchronous dependency tracing. | ||
135 | + | ||
136 | +The exception: calling AMD's callback-style require() from inside a factory | ||
137 | +function. The require callback is called on process.nextTick(): | ||
138 | + | ||
139 | +```javascript | ||
140 | +define(function (require) { | ||
141 | + require(['a'], function(a) { | ||
142 | + //'a' is loaded synchronously, but | ||
143 | + //this callback is called on process.nextTick(). | ||
144 | + }); | ||
145 | +}); | ||
146 | +``` | ||
147 | + | ||
148 | +### Loader Plugins | ||
149 | + | ||
150 | +Loader plugins are supported as long as they call their load() callbacks | ||
151 | +synchronously. So ones that do network requests will not work. However plugins | ||
152 | +like [text](http://requirejs.org/docs/api.html#text) can load text files locally. | ||
153 | + | ||
154 | +The plugin API's `load.fromText()` is **not supported** in amdefine, so this means | ||
155 | +transpiler plugins like the [CoffeeScript loader plugin](https://github.com/jrburke/require-cs) | ||
156 | +will not work. This may be fixable, but it is a bit complex, and I do not have | ||
157 | +enough node-fu to figure it out yet. See the source for amdefine.js if you want | ||
158 | +to get an idea of the issues involved. | ||
159 | + | ||
160 | +## Tests | ||
161 | + | ||
162 | +To run the tests, cd to **tests** and run: | ||
163 | + | ||
164 | +``` | ||
165 | +node all.js | ||
166 | +node all-intercept.js | ||
167 | +``` | ||
168 | + | ||
169 | +## License | ||
170 | + | ||
171 | +New BSD and MIT. Check the LICENSE file for all the details. |
1 | +/** vim: et:ts=4:sw=4:sts=4 | ||
2 | + * @license amdefine 1.0.1 Copyright (c) 2011-2016, The Dojo Foundation All Rights Reserved. | ||
3 | + * Available via the MIT or new BSD license. | ||
4 | + * see: http://github.com/jrburke/amdefine for details | ||
5 | + */ | ||
6 | + | ||
7 | +/*jslint node: true */ | ||
8 | +/*global module, process */ | ||
9 | +'use strict'; | ||
10 | + | ||
11 | +/** | ||
12 | + * Creates a define for node. | ||
13 | + * @param {Object} module the "module" object that is defined by Node for the | ||
14 | + * current module. | ||
15 | + * @param {Function} [requireFn]. Node's require function for the current module. | ||
16 | + * It only needs to be passed in Node versions before 0.5, when module.require | ||
17 | + * did not exist. | ||
18 | + * @returns {Function} a define function that is usable for the current node | ||
19 | + * module. | ||
20 | + */ | ||
21 | +function amdefine(module, requireFn) { | ||
22 | + 'use strict'; | ||
23 | + var defineCache = {}, | ||
24 | + loaderCache = {}, | ||
25 | + alreadyCalled = false, | ||
26 | + path = require('path'), | ||
27 | + makeRequire, stringRequire; | ||
28 | + | ||
29 | + /** | ||
30 | + * Trims the . and .. from an array of path segments. | ||
31 | + * It will keep a leading path segment if a .. will become | ||
32 | + * the first path segment, to help with module name lookups, | ||
33 | + * which act like paths, but can be remapped. But the end result, | ||
34 | + * all paths that use this function should look normalized. | ||
35 | + * NOTE: this method MODIFIES the input array. | ||
36 | + * @param {Array} ary the array of path segments. | ||
37 | + */ | ||
38 | + function trimDots(ary) { | ||
39 | + var i, part; | ||
40 | + for (i = 0; ary[i]; i+= 1) { | ||
41 | + part = ary[i]; | ||
42 | + if (part === '.') { | ||
43 | + ary.splice(i, 1); | ||
44 | + i -= 1; | ||
45 | + } else if (part === '..') { | ||
46 | + if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { | ||
47 | + //End of the line. Keep at least one non-dot | ||
48 | + //path segment at the front so it can be mapped | ||
49 | + //correctly to disk. Otherwise, there is likely | ||
50 | + //no path mapping for a path starting with '..'. | ||
51 | + //This can still fail, but catches the most reasonable | ||
52 | + //uses of .. | ||
53 | + break; | ||
54 | + } else if (i > 0) { | ||
55 | + ary.splice(i - 1, 2); | ||
56 | + i -= 2; | ||
57 | + } | ||
58 | + } | ||
59 | + } | ||
60 | + } | ||
61 | + | ||
62 | + function normalize(name, baseName) { | ||
63 | + var baseParts; | ||
64 | + | ||
65 | + //Adjust any relative paths. | ||
66 | + if (name && name.charAt(0) === '.') { | ||
67 | + //If have a base name, try to normalize against it, | ||
68 | + //otherwise, assume it is a top-level require that will | ||
69 | + //be relative to baseUrl in the end. | ||
70 | + if (baseName) { | ||
71 | + baseParts = baseName.split('/'); | ||
72 | + baseParts = baseParts.slice(0, baseParts.length - 1); | ||
73 | + baseParts = baseParts.concat(name.split('/')); | ||
74 | + trimDots(baseParts); | ||
75 | + name = baseParts.join('/'); | ||
76 | + } | ||
77 | + } | ||
78 | + | ||
79 | + return name; | ||
80 | + } | ||
81 | + | ||
82 | + /** | ||
83 | + * Create the normalize() function passed to a loader plugin's | ||
84 | + * normalize method. | ||
85 | + */ | ||
86 | + function makeNormalize(relName) { | ||
87 | + return function (name) { | ||
88 | + return normalize(name, relName); | ||
89 | + }; | ||
90 | + } | ||
91 | + | ||
92 | + function makeLoad(id) { | ||
93 | + function load(value) { | ||
94 | + loaderCache[id] = value; | ||
95 | + } | ||
96 | + | ||
97 | + load.fromText = function (id, text) { | ||
98 | + //This one is difficult because the text can/probably uses | ||
99 | + //define, and any relative paths and requires should be relative | ||
100 | + //to that id was it would be found on disk. But this would require | ||
101 | + //bootstrapping a module/require fairly deeply from node core. | ||
102 | + //Not sure how best to go about that yet. | ||
103 | + throw new Error('amdefine does not implement load.fromText'); | ||
104 | + }; | ||
105 | + | ||
106 | + return load; | ||
107 | + } | ||
108 | + | ||
109 | + makeRequire = function (systemRequire, exports, module, relId) { | ||
110 | + function amdRequire(deps, callback) { | ||
111 | + if (typeof deps === 'string') { | ||
112 | + //Synchronous, single module require('') | ||
113 | + return stringRequire(systemRequire, exports, module, deps, relId); | ||
114 | + } else { | ||
115 | + //Array of dependencies with a callback. | ||
116 | + | ||
117 | + //Convert the dependencies to modules. | ||
118 | + deps = deps.map(function (depName) { | ||
119 | + return stringRequire(systemRequire, exports, module, depName, relId); | ||
120 | + }); | ||
121 | + | ||
122 | + //Wait for next tick to call back the require call. | ||
123 | + if (callback) { | ||
124 | + process.nextTick(function () { | ||
125 | + callback.apply(null, deps); | ||
126 | + }); | ||
127 | + } | ||
128 | + } | ||
129 | + } | ||
130 | + | ||
131 | + amdRequire.toUrl = function (filePath) { | ||
132 | + if (filePath.indexOf('.') === 0) { | ||
133 | + return normalize(filePath, path.dirname(module.filename)); | ||
134 | + } else { | ||
135 | + return filePath; | ||
136 | + } | ||
137 | + }; | ||
138 | + | ||
139 | + return amdRequire; | ||
140 | + }; | ||
141 | + | ||
142 | + //Favor explicit value, passed in if the module wants to support Node 0.4. | ||
143 | + requireFn = requireFn || function req() { | ||
144 | + return module.require.apply(module, arguments); | ||
145 | + }; | ||
146 | + | ||
147 | + function runFactory(id, deps, factory) { | ||
148 | + var r, e, m, result; | ||
149 | + | ||
150 | + if (id) { | ||
151 | + e = loaderCache[id] = {}; | ||
152 | + m = { | ||
153 | + id: id, | ||
154 | + uri: __filename, | ||
155 | + exports: e | ||
156 | + }; | ||
157 | + r = makeRequire(requireFn, e, m, id); | ||
158 | + } else { | ||
159 | + //Only support one define call per file | ||
160 | + if (alreadyCalled) { | ||
161 | + throw new Error('amdefine with no module ID cannot be called more than once per file.'); | ||
162 | + } | ||
163 | + alreadyCalled = true; | ||
164 | + | ||
165 | + //Use the real variables from node | ||
166 | + //Use module.exports for exports, since | ||
167 | + //the exports in here is amdefine exports. | ||
168 | + e = module.exports; | ||
169 | + m = module; | ||
170 | + r = makeRequire(requireFn, e, m, module.id); | ||
171 | + } | ||
172 | + | ||
173 | + //If there are dependencies, they are strings, so need | ||
174 | + //to convert them to dependency values. | ||
175 | + if (deps) { | ||
176 | + deps = deps.map(function (depName) { | ||
177 | + return r(depName); | ||
178 | + }); | ||
179 | + } | ||
180 | + | ||
181 | + //Call the factory with the right dependencies. | ||
182 | + if (typeof factory === 'function') { | ||
183 | + result = factory.apply(m.exports, deps); | ||
184 | + } else { | ||
185 | + result = factory; | ||
186 | + } | ||
187 | + | ||
188 | + if (result !== undefined) { | ||
189 | + m.exports = result; | ||
190 | + if (id) { | ||
191 | + loaderCache[id] = m.exports; | ||
192 | + } | ||
193 | + } | ||
194 | + } | ||
195 | + | ||
196 | + stringRequire = function (systemRequire, exports, module, id, relId) { | ||
197 | + //Split the ID by a ! so that | ||
198 | + var index = id.indexOf('!'), | ||
199 | + originalId = id, | ||
200 | + prefix, plugin; | ||
201 | + | ||
202 | + if (index === -1) { | ||
203 | + id = normalize(id, relId); | ||
204 | + | ||
205 | + //Straight module lookup. If it is one of the special dependencies, | ||
206 | + //deal with it, otherwise, delegate to node. | ||
207 | + if (id === 'require') { | ||
208 | + return makeRequire(systemRequire, exports, module, relId); | ||
209 | + } else if (id === 'exports') { | ||
210 | + return exports; | ||
211 | + } else if (id === 'module') { | ||
212 | + return module; | ||
213 | + } else if (loaderCache.hasOwnProperty(id)) { | ||
214 | + return loaderCache[id]; | ||
215 | + } else if (defineCache[id]) { | ||
216 | + runFactory.apply(null, defineCache[id]); | ||
217 | + return loaderCache[id]; | ||
218 | + } else { | ||
219 | + if(systemRequire) { | ||
220 | + return systemRequire(originalId); | ||
221 | + } else { | ||
222 | + throw new Error('No module with ID: ' + id); | ||
223 | + } | ||
224 | + } | ||
225 | + } else { | ||
226 | + //There is a plugin in play. | ||
227 | + prefix = id.substring(0, index); | ||
228 | + id = id.substring(index + 1, id.length); | ||
229 | + | ||
230 | + plugin = stringRequire(systemRequire, exports, module, prefix, relId); | ||
231 | + | ||
232 | + if (plugin.normalize) { | ||
233 | + id = plugin.normalize(id, makeNormalize(relId)); | ||
234 | + } else { | ||
235 | + //Normalize the ID normally. | ||
236 | + id = normalize(id, relId); | ||
237 | + } | ||
238 | + | ||
239 | + if (loaderCache[id]) { | ||
240 | + return loaderCache[id]; | ||
241 | + } else { | ||
242 | + plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {}); | ||
243 | + | ||
244 | + return loaderCache[id]; | ||
245 | + } | ||
246 | + } | ||
247 | + }; | ||
248 | + | ||
249 | + //Create a define function specific to the module asking for amdefine. | ||
250 | + function define(id, deps, factory) { | ||
251 | + if (Array.isArray(id)) { | ||
252 | + factory = deps; | ||
253 | + deps = id; | ||
254 | + id = undefined; | ||
255 | + } else if (typeof id !== 'string') { | ||
256 | + factory = id; | ||
257 | + id = deps = undefined; | ||
258 | + } | ||
259 | + | ||
260 | + if (deps && !Array.isArray(deps)) { | ||
261 | + factory = deps; | ||
262 | + deps = undefined; | ||
263 | + } | ||
264 | + | ||
265 | + if (!deps) { | ||
266 | + deps = ['require', 'exports', 'module']; | ||
267 | + } | ||
268 | + | ||
269 | + //Set up properties for this module. If an ID, then use | ||
270 | + //internal cache. If no ID, then use the external variables | ||
271 | + //for this node module. | ||
272 | + if (id) { | ||
273 | + //Put the module in deep freeze until there is a | ||
274 | + //require call for it. | ||
275 | + defineCache[id] = [id, deps, factory]; | ||
276 | + } else { | ||
277 | + runFactory(id, deps, factory); | ||
278 | + } | ||
279 | + } | ||
280 | + | ||
281 | + //define.require, which has access to all the values in the | ||
282 | + //cache. Useful for AMD modules that all have IDs in the file, | ||
283 | + //but need to finally export a value to node based on one of those | ||
284 | + //IDs. | ||
285 | + define.require = function (id) { | ||
286 | + if (loaderCache[id]) { | ||
287 | + return loaderCache[id]; | ||
288 | + } | ||
289 | + | ||
290 | + if (defineCache[id]) { | ||
291 | + runFactory.apply(null, defineCache[id]); | ||
292 | + return loaderCache[id]; | ||
293 | + } | ||
294 | + }; | ||
295 | + | ||
296 | + define.amd = {}; | ||
297 | + | ||
298 | + return define; | ||
299 | +} | ||
300 | + | ||
301 | +module.exports = amdefine; |
1 | +/*jshint node: true */ | ||
2 | +var inserted, | ||
3 | + Module = require('module'), | ||
4 | + fs = require('fs'), | ||
5 | + existingExtFn = Module._extensions['.js'], | ||
6 | + amdefineRegExp = /amdefine\.js/; | ||
7 | + | ||
8 | +inserted = "if (typeof define !== 'function') {var define = require('amdefine')(module)}"; | ||
9 | + | ||
10 | +//From the node/lib/module.js source: | ||
11 | +function stripBOM(content) { | ||
12 | + // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) | ||
13 | + // because the buffer-to-string conversion in `fs.readFileSync()` | ||
14 | + // translates it to FEFF, the UTF-16 BOM. | ||
15 | + if (content.charCodeAt(0) === 0xFEFF) { | ||
16 | + content = content.slice(1); | ||
17 | + } | ||
18 | + return content; | ||
19 | +} | ||
20 | + | ||
21 | +//Also adapted from the node/lib/module.js source: | ||
22 | +function intercept(module, filename) { | ||
23 | + var content = stripBOM(fs.readFileSync(filename, 'utf8')); | ||
24 | + | ||
25 | + if (!amdefineRegExp.test(module.id)) { | ||
26 | + content = inserted + content; | ||
27 | + } | ||
28 | + | ||
29 | + module._compile(content, filename); | ||
30 | +} | ||
31 | + | ||
32 | +intercept._id = 'amdefine/intercept'; | ||
33 | + | ||
34 | +if (!existingExtFn._id || existingExtFn._id !== intercept._id) { | ||
35 | + Module._extensions['.js'] = intercept; | ||
36 | +} |
1 | +{ | ||
2 | + "_from": "amdefine@>=0.0.4", | ||
3 | + "_id": "amdefine@1.0.1", | ||
4 | + "_inBundle": false, | ||
5 | + "_integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", | ||
6 | + "_location": "/amdefine", | ||
7 | + "_phantomChildren": {}, | ||
8 | + "_requested": { | ||
9 | + "type": "range", | ||
10 | + "registry": true, | ||
11 | + "raw": "amdefine@>=0.0.4", | ||
12 | + "name": "amdefine", | ||
13 | + "escapedName": "amdefine", | ||
14 | + "rawSpec": ">=0.0.4", | ||
15 | + "saveSpec": null, | ||
16 | + "fetchSpec": ">=0.0.4" | ||
17 | + }, | ||
18 | + "_requiredBy": [ | ||
19 | + "/source-map" | ||
20 | + ], | ||
21 | + "_resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", | ||
22 | + "_shasum": "4a5282ac164729e93619bcfd3ad151f817ce91f5", | ||
23 | + "_spec": "amdefine@>=0.0.4", | ||
24 | + "_where": "C:\\Users\\경훈\\Desktop\\nodejs-todo-list-master\\nodejs-todo-list-master\\node_modules\\source-map", | ||
25 | + "author": { | ||
26 | + "name": "James Burke", | ||
27 | + "email": "jrburke@gmail.com", | ||
28 | + "url": "http://github.com/jrburke" | ||
29 | + }, | ||
30 | + "bugs": { | ||
31 | + "url": "https://github.com/jrburke/amdefine/issues" | ||
32 | + }, | ||
33 | + "bundleDependencies": false, | ||
34 | + "deprecated": false, | ||
35 | + "description": "Provide AMD's define() API for declaring modules in the AMD format", | ||
36 | + "engines": { | ||
37 | + "node": ">=0.4.2" | ||
38 | + }, | ||
39 | + "homepage": "http://github.com/jrburke/amdefine", | ||
40 | + "license": "BSD-3-Clause OR MIT", | ||
41 | + "main": "./amdefine.js", | ||
42 | + "name": "amdefine", | ||
43 | + "repository": { | ||
44 | + "type": "git", | ||
45 | + "url": "git+https://github.com/jrburke/amdefine.git" | ||
46 | + }, | ||
47 | + "version": "1.0.1" | ||
48 | +} |
... | @@ -21,7 +21,7 @@ | ... | @@ -21,7 +21,7 @@ |
21 | "_resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", | 21 | "_resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", |
22 | "_shasum": "8d2475dfab553bb33e77b54e59e880bb8ce23136", | 22 | "_shasum": "8d2475dfab553bb33e77b54e59e880bb8ce23136", |
23 | "_spec": "asn1@~0.2.3", | 23 | "_spec": "asn1@~0.2.3", |
24 | - "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\sshpk", | 24 | + "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\nodejs-todo-list-master\\node_modules\\sshpk", |
25 | "author": { | 25 | "author": { |
26 | "name": "Joyent", | 26 | "name": "Joyent", |
27 | "url": "joyent.com" | 27 | "url": "joyent.com" | ... | ... |
... | @@ -26,7 +26,7 @@ | ... | @@ -26,7 +26,7 @@ |
26 | "_resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", | 26 | "_resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", |
27 | "_shasum": "f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525", | 27 | "_shasum": "f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525", |
28 | "_spec": "assert-plus@^1.0.0", | 28 | "_spec": "assert-plus@^1.0.0", |
29 | - "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\http-signature", | 29 | + "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\nodejs-todo-list-master\\node_modules\\http-signature", |
30 | "author": { | 30 | "author": { |
31 | "name": "Mark Cavage", | 31 | "name": "Mark Cavage", |
32 | "email": "mcavage@gmail.com" | 32 | "email": "mcavage@gmail.com" | ... | ... |
... | @@ -21,7 +21,7 @@ | ... | @@ -21,7 +21,7 @@ |
21 | "_resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", | 21 | "_resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", |
22 | "_shasum": "c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79", | 22 | "_shasum": "c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79", |
23 | "_spec": "asynckit@^0.4.0", | 23 | "_spec": "asynckit@^0.4.0", |
24 | - "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\form-data", | 24 | + "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\nodejs-todo-list-master\\node_modules\\form-data", |
25 | "author": { | 25 | "author": { |
26 | "name": "Alex Indigo", | 26 | "name": "Alex Indigo", |
27 | "email": "iam@alexindigo.com" | 27 | "email": "iam@alexindigo.com" | ... | ... |
... | @@ -21,7 +21,7 @@ | ... | @@ -21,7 +21,7 @@ |
21 | "_resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", | 21 | "_resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", |
22 | "_shasum": "b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8", | 22 | "_shasum": "b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8", |
23 | "_spec": "aws-sign2@~0.7.0", | 23 | "_spec": "aws-sign2@~0.7.0", |
24 | - "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\request", | 24 | + "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\nodejs-todo-list-master\\node_modules\\request", |
25 | "author": { | 25 | "author": { |
26 | "name": "Mikeal Rogers", | 26 | "name": "Mikeal Rogers", |
27 | "email": "mikeal.rogers@gmail.com", | 27 | "email": "mikeal.rogers@gmail.com", | ... | ... |
... | @@ -21,7 +21,7 @@ | ... | @@ -21,7 +21,7 @@ |
21 | "_resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", | 21 | "_resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", |
22 | "_shasum": "f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f", | 22 | "_shasum": "f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f", |
23 | "_spec": "aws4@^1.8.0", | 23 | "_spec": "aws4@^1.8.0", |
24 | - "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\request", | 24 | + "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\nodejs-todo-list-master\\node_modules\\request", |
25 | "author": { | 25 | "author": { |
26 | "name": "Michael Hart", | 26 | "name": "Michael Hart", |
27 | "email": "michael.hart.au@gmail.com", | 27 | "email": "michael.hart.au@gmail.com", | ... | ... |
1 | +(MIT) | ||
2 | + | ||
3 | +Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> | ||
4 | + | ||
5 | +Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
6 | +this software and associated documentation files (the "Software"), to deal in | ||
7 | +the Software without restriction, including without limitation the rights to | ||
8 | +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||
9 | +of the Software, and to permit persons to whom the Software is furnished to do | ||
10 | +so, subject to the following conditions: | ||
11 | + | ||
12 | +The above copyright notice and this permission notice shall be included in all | ||
13 | +copies or substantial portions of the Software. | ||
14 | + | ||
15 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
21 | +SOFTWARE. |
1 | +# balanced-match | ||
2 | + | ||
3 | +Match balanced string pairs, like `{` and `}` or `<b>` and `</b>`. Supports regular expressions as well! | ||
4 | + | ||
5 | +[![build status](https://secure.travis-ci.org/juliangruber/balanced-match.svg)](http://travis-ci.org/juliangruber/balanced-match) | ||
6 | +[![downloads](https://img.shields.io/npm/dm/balanced-match.svg)](https://www.npmjs.org/package/balanced-match) | ||
7 | + | ||
8 | +[![testling badge](https://ci.testling.com/juliangruber/balanced-match.png)](https://ci.testling.com/juliangruber/balanced-match) | ||
9 | + | ||
10 | +## Example | ||
11 | + | ||
12 | +Get the first matching pair of braces: | ||
13 | + | ||
14 | +```js | ||
15 | +var balanced = require('balanced-match'); | ||
16 | + | ||
17 | +console.log(balanced('{', '}', 'pre{in{nested}}post')); | ||
18 | +console.log(balanced('{', '}', 'pre{first}between{second}post')); | ||
19 | +console.log(balanced(/\s+\{\s+/, /\s+\}\s+/, 'pre { in{nest} } post')); | ||
20 | +``` | ||
21 | + | ||
22 | +The matches are: | ||
23 | + | ||
24 | +```bash | ||
25 | +$ node example.js | ||
26 | +{ start: 3, end: 14, pre: 'pre', body: 'in{nested}', post: 'post' } | ||
27 | +{ start: 3, | ||
28 | + end: 9, | ||
29 | + pre: 'pre', | ||
30 | + body: 'first', | ||
31 | + post: 'between{second}post' } | ||
32 | +{ start: 3, end: 17, pre: 'pre', body: 'in{nest}', post: 'post' } | ||
33 | +``` | ||
34 | + | ||
35 | +## API | ||
36 | + | ||
37 | +### var m = balanced(a, b, str) | ||
38 | + | ||
39 | +For the first non-nested matching pair of `a` and `b` in `str`, return an | ||
40 | +object with those keys: | ||
41 | + | ||
42 | +* **start** the index of the first match of `a` | ||
43 | +* **end** the index of the matching `b` | ||
44 | +* **pre** the preamble, `a` and `b` not included | ||
45 | +* **body** the match, `a` and `b` not included | ||
46 | +* **post** the postscript, `a` and `b` not included | ||
47 | + | ||
48 | +If there's no match, `undefined` will be returned. | ||
49 | + | ||
50 | +If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `['{', 'a', '']` and `{a}}` will match `['', 'a', '}']`. | ||
51 | + | ||
52 | +### var r = balanced.range(a, b, str) | ||
53 | + | ||
54 | +For the first non-nested matching pair of `a` and `b` in `str`, return an | ||
55 | +array with indexes: `[ <a index>, <b index> ]`. | ||
56 | + | ||
57 | +If there's no match, `undefined` will be returned. | ||
58 | + | ||
59 | +If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `[ 1, 3 ]` and `{a}}` will match `[0, 2]`. | ||
60 | + | ||
61 | +## Installation | ||
62 | + | ||
63 | +With [npm](https://npmjs.org) do: | ||
64 | + | ||
65 | +```bash | ||
66 | +npm install balanced-match | ||
67 | +``` | ||
68 | + | ||
69 | +## License | ||
70 | + | ||
71 | +(MIT) | ||
72 | + | ||
73 | +Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> | ||
74 | + | ||
75 | +Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
76 | +this software and associated documentation files (the "Software"), to deal in | ||
77 | +the Software without restriction, including without limitation the rights to | ||
78 | +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||
79 | +of the Software, and to permit persons to whom the Software is furnished to do | ||
80 | +so, subject to the following conditions: | ||
81 | + | ||
82 | +The above copyright notice and this permission notice shall be included in all | ||
83 | +copies or substantial portions of the Software. | ||
84 | + | ||
85 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
86 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
87 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
88 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
89 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
90 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
91 | +SOFTWARE. |
1 | +'use strict'; | ||
2 | +module.exports = balanced; | ||
3 | +function balanced(a, b, str) { | ||
4 | + if (a instanceof RegExp) a = maybeMatch(a, str); | ||
5 | + if (b instanceof RegExp) b = maybeMatch(b, str); | ||
6 | + | ||
7 | + var r = range(a, b, str); | ||
8 | + | ||
9 | + return r && { | ||
10 | + start: r[0], | ||
11 | + end: r[1], | ||
12 | + pre: str.slice(0, r[0]), | ||
13 | + body: str.slice(r[0] + a.length, r[1]), | ||
14 | + post: str.slice(r[1] + b.length) | ||
15 | + }; | ||
16 | +} | ||
17 | + | ||
18 | +function maybeMatch(reg, str) { | ||
19 | + var m = str.match(reg); | ||
20 | + return m ? m[0] : null; | ||
21 | +} | ||
22 | + | ||
23 | +balanced.range = range; | ||
24 | +function range(a, b, str) { | ||
25 | + var begs, beg, left, right, result; | ||
26 | + var ai = str.indexOf(a); | ||
27 | + var bi = str.indexOf(b, ai + 1); | ||
28 | + var i = ai; | ||
29 | + | ||
30 | + if (ai >= 0 && bi > 0) { | ||
31 | + begs = []; | ||
32 | + left = str.length; | ||
33 | + | ||
34 | + while (i >= 0 && !result) { | ||
35 | + if (i == ai) { | ||
36 | + begs.push(i); | ||
37 | + ai = str.indexOf(a, i + 1); | ||
38 | + } else if (begs.length == 1) { | ||
39 | + result = [ begs.pop(), bi ]; | ||
40 | + } else { | ||
41 | + beg = begs.pop(); | ||
42 | + if (beg < left) { | ||
43 | + left = beg; | ||
44 | + right = bi; | ||
45 | + } | ||
46 | + | ||
47 | + bi = str.indexOf(b, i + 1); | ||
48 | + } | ||
49 | + | ||
50 | + i = ai < bi && ai >= 0 ? ai : bi; | ||
51 | + } | ||
52 | + | ||
53 | + if (begs.length) { | ||
54 | + result = [ left, right ]; | ||
55 | + } | ||
56 | + } | ||
57 | + | ||
58 | + return result; | ||
59 | +} |
1 | +{ | ||
2 | + "_from": "balanced-match@^1.0.0", | ||
3 | + "_id": "balanced-match@1.0.0", | ||
4 | + "_inBundle": false, | ||
5 | + "_integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", | ||
6 | + "_location": "/balanced-match", | ||
7 | + "_phantomChildren": {}, | ||
8 | + "_requested": { | ||
9 | + "type": "range", | ||
10 | + "registry": true, | ||
11 | + "raw": "balanced-match@^1.0.0", | ||
12 | + "name": "balanced-match", | ||
13 | + "escapedName": "balanced-match", | ||
14 | + "rawSpec": "^1.0.0", | ||
15 | + "saveSpec": null, | ||
16 | + "fetchSpec": "^1.0.0" | ||
17 | + }, | ||
18 | + "_requiredBy": [ | ||
19 | + "/brace-expansion" | ||
20 | + ], | ||
21 | + "_resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", | ||
22 | + "_shasum": "89b4d199ab2bee49de164ea02b89ce462d71b767", | ||
23 | + "_spec": "balanced-match@^1.0.0", | ||
24 | + "_where": "C:\\Users\\경훈\\Desktop\\nodejs-todo-list-master\\nodejs-todo-list-master\\node_modules\\brace-expansion", | ||
25 | + "author": { | ||
26 | + "name": "Julian Gruber", | ||
27 | + "email": "mail@juliangruber.com", | ||
28 | + "url": "http://juliangruber.com" | ||
29 | + }, | ||
30 | + "bugs": { | ||
31 | + "url": "https://github.com/juliangruber/balanced-match/issues" | ||
32 | + }, | ||
33 | + "bundleDependencies": false, | ||
34 | + "dependencies": {}, | ||
35 | + "deprecated": false, | ||
36 | + "description": "Match balanced character pairs, like \"{\" and \"}\"", | ||
37 | + "devDependencies": { | ||
38 | + "matcha": "^0.7.0", | ||
39 | + "tape": "^4.6.0" | ||
40 | + }, | ||
41 | + "homepage": "https://github.com/juliangruber/balanced-match", | ||
42 | + "keywords": [ | ||
43 | + "match", | ||
44 | + "regexp", | ||
45 | + "test", | ||
46 | + "balanced", | ||
47 | + "parse" | ||
48 | + ], | ||
49 | + "license": "MIT", | ||
50 | + "main": "index.js", | ||
51 | + "name": "balanced-match", | ||
52 | + "repository": { | ||
53 | + "type": "git", | ||
54 | + "url": "git://github.com/juliangruber/balanced-match.git" | ||
55 | + }, | ||
56 | + "scripts": { | ||
57 | + "bench": "make bench", | ||
58 | + "test": "make test" | ||
59 | + }, | ||
60 | + "testling": { | ||
61 | + "files": "test/*.js", | ||
62 | + "browsers": [ | ||
63 | + "ie/8..latest", | ||
64 | + "firefox/20..latest", | ||
65 | + "firefox/nightly", | ||
66 | + "chrome/25..latest", | ||
67 | + "chrome/canary", | ||
68 | + "opera/12..latest", | ||
69 | + "opera/next", | ||
70 | + "safari/5.1..latest", | ||
71 | + "ipad/6.0..latest", | ||
72 | + "iphone/6.0..latest", | ||
73 | + "android-browser/4.2..latest" | ||
74 | + ] | ||
75 | + }, | ||
76 | + "version": "1.0.0" | ||
77 | +} |
... | @@ -21,7 +21,7 @@ | ... | @@ -21,7 +21,7 @@ |
21 | "_resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", | 21 | "_resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", |
22 | "_shasum": "a4301d389b6a43f9b67ff3ca11a3f6637e360e9e", | 22 | "_shasum": "a4301d389b6a43f9b67ff3ca11a3f6637e360e9e", |
23 | "_spec": "bcrypt-pbkdf@^1.0.0", | 23 | "_spec": "bcrypt-pbkdf@^1.0.0", |
24 | - "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\sshpk", | 24 | + "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\nodejs-todo-list-master\\node_modules\\sshpk", |
25 | "bugs": { | 25 | "bugs": { |
26 | "url": "https://github.com/joyent/node-bcrypt-pbkdf/issues" | 26 | "url": "https://github.com/joyent/node-bcrypt-pbkdf/issues" |
27 | }, | 27 | }, | ... | ... |
1 | +MIT License | ||
2 | + | ||
3 | +Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> | ||
4 | + | ||
5 | +Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | +of this software and associated documentation files (the "Software"), to deal | ||
7 | +in the Software without restriction, including without limitation the rights | ||
8 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | +copies of the Software, and to permit persons to whom the Software is | ||
10 | +furnished to do so, subject to the following conditions: | ||
11 | + | ||
12 | +The above copyright notice and this permission notice shall be included in all | ||
13 | +copies or substantial portions of the Software. | ||
14 | + | ||
15 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
21 | +SOFTWARE. |
1 | +# brace-expansion | ||
2 | + | ||
3 | +[Brace expansion](https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html), | ||
4 | +as known from sh/bash, in JavaScript. | ||
5 | + | ||
6 | +[![build status](https://secure.travis-ci.org/juliangruber/brace-expansion.svg)](http://travis-ci.org/juliangruber/brace-expansion) | ||
7 | +[![downloads](https://img.shields.io/npm/dm/brace-expansion.svg)](https://www.npmjs.org/package/brace-expansion) | ||
8 | +[![Greenkeeper badge](https://badges.greenkeeper.io/juliangruber/brace-expansion.svg)](https://greenkeeper.io/) | ||
9 | + | ||
10 | +[![testling badge](https://ci.testling.com/juliangruber/brace-expansion.png)](https://ci.testling.com/juliangruber/brace-expansion) | ||
11 | + | ||
12 | +## Example | ||
13 | + | ||
14 | +```js | ||
15 | +var expand = require('brace-expansion'); | ||
16 | + | ||
17 | +expand('file-{a,b,c}.jpg') | ||
18 | +// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg'] | ||
19 | + | ||
20 | +expand('-v{,,}') | ||
21 | +// => ['-v', '-v', '-v'] | ||
22 | + | ||
23 | +expand('file{0..2}.jpg') | ||
24 | +// => ['file0.jpg', 'file1.jpg', 'file2.jpg'] | ||
25 | + | ||
26 | +expand('file-{a..c}.jpg') | ||
27 | +// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg'] | ||
28 | + | ||
29 | +expand('file{2..0}.jpg') | ||
30 | +// => ['file2.jpg', 'file1.jpg', 'file0.jpg'] | ||
31 | + | ||
32 | +expand('file{0..4..2}.jpg') | ||
33 | +// => ['file0.jpg', 'file2.jpg', 'file4.jpg'] | ||
34 | + | ||
35 | +expand('file-{a..e..2}.jpg') | ||
36 | +// => ['file-a.jpg', 'file-c.jpg', 'file-e.jpg'] | ||
37 | + | ||
38 | +expand('file{00..10..5}.jpg') | ||
39 | +// => ['file00.jpg', 'file05.jpg', 'file10.jpg'] | ||
40 | + | ||
41 | +expand('{{A..C},{a..c}}') | ||
42 | +// => ['A', 'B', 'C', 'a', 'b', 'c'] | ||
43 | + | ||
44 | +expand('ppp{,config,oe{,conf}}') | ||
45 | +// => ['ppp', 'pppconfig', 'pppoe', 'pppoeconf'] | ||
46 | +``` | ||
47 | + | ||
48 | +## API | ||
49 | + | ||
50 | +```js | ||
51 | +var expand = require('brace-expansion'); | ||
52 | +``` | ||
53 | + | ||
54 | +### var expanded = expand(str) | ||
55 | + | ||
56 | +Return an array of all possible and valid expansions of `str`. If none are | ||
57 | +found, `[str]` is returned. | ||
58 | + | ||
59 | +Valid expansions are: | ||
60 | + | ||
61 | +```js | ||
62 | +/^(.*,)+(.+)?$/ | ||
63 | +// {a,b,...} | ||
64 | +``` | ||
65 | + | ||
66 | +A comma separated list of options, like `{a,b}` or `{a,{b,c}}` or `{,a,}`. | ||
67 | + | ||
68 | +```js | ||
69 | +/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/ | ||
70 | +// {x..y[..incr]} | ||
71 | +``` | ||
72 | + | ||
73 | +A numeric sequence from `x` to `y` inclusive, with optional increment. | ||
74 | +If `x` or `y` start with a leading `0`, all the numbers will be padded | ||
75 | +to have equal length. Negative numbers and backwards iteration work too. | ||
76 | + | ||
77 | +```js | ||
78 | +/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/ | ||
79 | +// {x..y[..incr]} | ||
80 | +``` | ||
81 | + | ||
82 | +An alphabetic sequence from `x` to `y` inclusive, with optional increment. | ||
83 | +`x` and `y` must be exactly one character, and if given, `incr` must be a | ||
84 | +number. | ||
85 | + | ||
86 | +For compatibility reasons, the string `${` is not eligible for brace expansion. | ||
87 | + | ||
88 | +## Installation | ||
89 | + | ||
90 | +With [npm](https://npmjs.org) do: | ||
91 | + | ||
92 | +```bash | ||
93 | +npm install brace-expansion | ||
94 | +``` | ||
95 | + | ||
96 | +## Contributors | ||
97 | + | ||
98 | +- [Julian Gruber](https://github.com/juliangruber) | ||
99 | +- [Isaac Z. Schlueter](https://github.com/isaacs) | ||
100 | + | ||
101 | +## Sponsors | ||
102 | + | ||
103 | +This module is proudly supported by my [Sponsors](https://github.com/juliangruber/sponsors)! | ||
104 | + | ||
105 | +Do you want to support modules like this to improve their quality, stability and weigh in on new features? Then please consider donating to my [Patreon](https://www.patreon.com/juliangruber). Not sure how much of my modules you're using? Try [feross/thanks](https://github.com/feross/thanks)! | ||
106 | + | ||
107 | +## License | ||
108 | + | ||
109 | +(MIT) | ||
110 | + | ||
111 | +Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> | ||
112 | + | ||
113 | +Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
114 | +this software and associated documentation files (the "Software"), to deal in | ||
115 | +the Software without restriction, including without limitation the rights to | ||
116 | +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||
117 | +of the Software, and to permit persons to whom the Software is furnished to do | ||
118 | +so, subject to the following conditions: | ||
119 | + | ||
120 | +The above copyright notice and this permission notice shall be included in all | ||
121 | +copies or substantial portions of the Software. | ||
122 | + | ||
123 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
124 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
125 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
126 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
127 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
128 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
129 | +SOFTWARE. |
1 | +var concatMap = require('concat-map'); | ||
2 | +var balanced = require('balanced-match'); | ||
3 | + | ||
4 | +module.exports = expandTop; | ||
5 | + | ||
6 | +var escSlash = '\0SLASH'+Math.random()+'\0'; | ||
7 | +var escOpen = '\0OPEN'+Math.random()+'\0'; | ||
8 | +var escClose = '\0CLOSE'+Math.random()+'\0'; | ||
9 | +var escComma = '\0COMMA'+Math.random()+'\0'; | ||
10 | +var escPeriod = '\0PERIOD'+Math.random()+'\0'; | ||
11 | + | ||
12 | +function numeric(str) { | ||
13 | + return parseInt(str, 10) == str | ||
14 | + ? parseInt(str, 10) | ||
15 | + : str.charCodeAt(0); | ||
16 | +} | ||
17 | + | ||
18 | +function escapeBraces(str) { | ||
19 | + return str.split('\\\\').join(escSlash) | ||
20 | + .split('\\{').join(escOpen) | ||
21 | + .split('\\}').join(escClose) | ||
22 | + .split('\\,').join(escComma) | ||
23 | + .split('\\.').join(escPeriod); | ||
24 | +} | ||
25 | + | ||
26 | +function unescapeBraces(str) { | ||
27 | + return str.split(escSlash).join('\\') | ||
28 | + .split(escOpen).join('{') | ||
29 | + .split(escClose).join('}') | ||
30 | + .split(escComma).join(',') | ||
31 | + .split(escPeriod).join('.'); | ||
32 | +} | ||
33 | + | ||
34 | + | ||
35 | +// Basically just str.split(","), but handling cases | ||
36 | +// where we have nested braced sections, which should be | ||
37 | +// treated as individual members, like {a,{b,c},d} | ||
38 | +function parseCommaParts(str) { | ||
39 | + if (!str) | ||
40 | + return ['']; | ||
41 | + | ||
42 | + var parts = []; | ||
43 | + var m = balanced('{', '}', str); | ||
44 | + | ||
45 | + if (!m) | ||
46 | + return str.split(','); | ||
47 | + | ||
48 | + var pre = m.pre; | ||
49 | + var body = m.body; | ||
50 | + var post = m.post; | ||
51 | + var p = pre.split(','); | ||
52 | + | ||
53 | + p[p.length-1] += '{' + body + '}'; | ||
54 | + var postParts = parseCommaParts(post); | ||
55 | + if (post.length) { | ||
56 | + p[p.length-1] += postParts.shift(); | ||
57 | + p.push.apply(p, postParts); | ||
58 | + } | ||
59 | + | ||
60 | + parts.push.apply(parts, p); | ||
61 | + | ||
62 | + return parts; | ||
63 | +} | ||
64 | + | ||
65 | +function expandTop(str) { | ||
66 | + if (!str) | ||
67 | + return []; | ||
68 | + | ||
69 | + // I don't know why Bash 4.3 does this, but it does. | ||
70 | + // Anything starting with {} will have the first two bytes preserved | ||
71 | + // but *only* at the top level, so {},a}b will not expand to anything, | ||
72 | + // but a{},b}c will be expanded to [a}c,abc]. | ||
73 | + // One could argue that this is a bug in Bash, but since the goal of | ||
74 | + // this module is to match Bash's rules, we escape a leading {} | ||
75 | + if (str.substr(0, 2) === '{}') { | ||
76 | + str = '\\{\\}' + str.substr(2); | ||
77 | + } | ||
78 | + | ||
79 | + return expand(escapeBraces(str), true).map(unescapeBraces); | ||
80 | +} | ||
81 | + | ||
82 | +function identity(e) { | ||
83 | + return e; | ||
84 | +} | ||
85 | + | ||
86 | +function embrace(str) { | ||
87 | + return '{' + str + '}'; | ||
88 | +} | ||
89 | +function isPadded(el) { | ||
90 | + return /^-?0\d/.test(el); | ||
91 | +} | ||
92 | + | ||
93 | +function lte(i, y) { | ||
94 | + return i <= y; | ||
95 | +} | ||
96 | +function gte(i, y) { | ||
97 | + return i >= y; | ||
98 | +} | ||
99 | + | ||
100 | +function expand(str, isTop) { | ||
101 | + var expansions = []; | ||
102 | + | ||
103 | + var m = balanced('{', '}', str); | ||
104 | + if (!m || /\$$/.test(m.pre)) return [str]; | ||
105 | + | ||
106 | + var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); | ||
107 | + var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); | ||
108 | + var isSequence = isNumericSequence || isAlphaSequence; | ||
109 | + var isOptions = m.body.indexOf(',') >= 0; | ||
110 | + if (!isSequence && !isOptions) { | ||
111 | + // {a},b} | ||
112 | + if (m.post.match(/,.*\}/)) { | ||
113 | + str = m.pre + '{' + m.body + escClose + m.post; | ||
114 | + return expand(str); | ||
115 | + } | ||
116 | + return [str]; | ||
117 | + } | ||
118 | + | ||
119 | + var n; | ||
120 | + if (isSequence) { | ||
121 | + n = m.body.split(/\.\./); | ||
122 | + } else { | ||
123 | + n = parseCommaParts(m.body); | ||
124 | + if (n.length === 1) { | ||
125 | + // x{{a,b}}y ==> x{a}y x{b}y | ||
126 | + n = expand(n[0], false).map(embrace); | ||
127 | + if (n.length === 1) { | ||
128 | + var post = m.post.length | ||
129 | + ? expand(m.post, false) | ||
130 | + : ['']; | ||
131 | + return post.map(function(p) { | ||
132 | + return m.pre + n[0] + p; | ||
133 | + }); | ||
134 | + } | ||
135 | + } | ||
136 | + } | ||
137 | + | ||
138 | + // at this point, n is the parts, and we know it's not a comma set | ||
139 | + // with a single entry. | ||
140 | + | ||
141 | + // no need to expand pre, since it is guaranteed to be free of brace-sets | ||
142 | + var pre = m.pre; | ||
143 | + var post = m.post.length | ||
144 | + ? expand(m.post, false) | ||
145 | + : ['']; | ||
146 | + | ||
147 | + var N; | ||
148 | + | ||
149 | + if (isSequence) { | ||
150 | + var x = numeric(n[0]); | ||
151 | + var y = numeric(n[1]); | ||
152 | + var width = Math.max(n[0].length, n[1].length) | ||
153 | + var incr = n.length == 3 | ||
154 | + ? Math.abs(numeric(n[2])) | ||
155 | + : 1; | ||
156 | + var test = lte; | ||
157 | + var reverse = y < x; | ||
158 | + if (reverse) { | ||
159 | + incr *= -1; | ||
160 | + test = gte; | ||
161 | + } | ||
162 | + var pad = n.some(isPadded); | ||
163 | + | ||
164 | + N = []; | ||
165 | + | ||
166 | + for (var i = x; test(i, y); i += incr) { | ||
167 | + var c; | ||
168 | + if (isAlphaSequence) { | ||
169 | + c = String.fromCharCode(i); | ||
170 | + if (c === '\\') | ||
171 | + c = ''; | ||
172 | + } else { | ||
173 | + c = String(i); | ||
174 | + if (pad) { | ||
175 | + var need = width - c.length; | ||
176 | + if (need > 0) { | ||
177 | + var z = new Array(need + 1).join('0'); | ||
178 | + if (i < 0) | ||
179 | + c = '-' + z + c.slice(1); | ||
180 | + else | ||
181 | + c = z + c; | ||
182 | + } | ||
183 | + } | ||
184 | + } | ||
185 | + N.push(c); | ||
186 | + } | ||
187 | + } else { | ||
188 | + N = concatMap(n, function(el) { return expand(el, false) }); | ||
189 | + } | ||
190 | + | ||
191 | + for (var j = 0; j < N.length; j++) { | ||
192 | + for (var k = 0; k < post.length; k++) { | ||
193 | + var expansion = pre + N[j] + post[k]; | ||
194 | + if (!isTop || isSequence || expansion) | ||
195 | + expansions.push(expansion); | ||
196 | + } | ||
197 | + } | ||
198 | + | ||
199 | + return expansions; | ||
200 | +} | ||
201 | + |
1 | +{ | ||
2 | + "_from": "brace-expansion@^1.1.7", | ||
3 | + "_id": "brace-expansion@1.1.11", | ||
4 | + "_inBundle": false, | ||
5 | + "_integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", | ||
6 | + "_location": "/brace-expansion", | ||
7 | + "_phantomChildren": {}, | ||
8 | + "_requested": { | ||
9 | + "type": "range", | ||
10 | + "registry": true, | ||
11 | + "raw": "brace-expansion@^1.1.7", | ||
12 | + "name": "brace-expansion", | ||
13 | + "escapedName": "brace-expansion", | ||
14 | + "rawSpec": "^1.1.7", | ||
15 | + "saveSpec": null, | ||
16 | + "fetchSpec": "^1.1.7" | ||
17 | + }, | ||
18 | + "_requiredBy": [ | ||
19 | + "/minimatch" | ||
20 | + ], | ||
21 | + "_resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", | ||
22 | + "_shasum": "3c7fcbf529d87226f3d2f52b966ff5271eb441dd", | ||
23 | + "_spec": "brace-expansion@^1.1.7", | ||
24 | + "_where": "C:\\Users\\경훈\\Desktop\\nodejs-todo-list-master\\nodejs-todo-list-master\\node_modules\\minimatch", | ||
25 | + "author": { | ||
26 | + "name": "Julian Gruber", | ||
27 | + "email": "mail@juliangruber.com", | ||
28 | + "url": "http://juliangruber.com" | ||
29 | + }, | ||
30 | + "bugs": { | ||
31 | + "url": "https://github.com/juliangruber/brace-expansion/issues" | ||
32 | + }, | ||
33 | + "bundleDependencies": false, | ||
34 | + "dependencies": { | ||
35 | + "balanced-match": "^1.0.0", | ||
36 | + "concat-map": "0.0.1" | ||
37 | + }, | ||
38 | + "deprecated": false, | ||
39 | + "description": "Brace expansion as known from sh/bash", | ||
40 | + "devDependencies": { | ||
41 | + "matcha": "^0.7.0", | ||
42 | + "tape": "^4.6.0" | ||
43 | + }, | ||
44 | + "homepage": "https://github.com/juliangruber/brace-expansion", | ||
45 | + "keywords": [], | ||
46 | + "license": "MIT", | ||
47 | + "main": "index.js", | ||
48 | + "name": "brace-expansion", | ||
49 | + "repository": { | ||
50 | + "type": "git", | ||
51 | + "url": "git://github.com/juliangruber/brace-expansion.git" | ||
52 | + }, | ||
53 | + "scripts": { | ||
54 | + "bench": "matcha test/perf/bench.js", | ||
55 | + "gentest": "bash test/generate.sh", | ||
56 | + "test": "tape test/*.js" | ||
57 | + }, | ||
58 | + "testling": { | ||
59 | + "files": "test/*.js", | ||
60 | + "browsers": [ | ||
61 | + "ie/8..latest", | ||
62 | + "firefox/20..latest", | ||
63 | + "firefox/nightly", | ||
64 | + "chrome/25..latest", | ||
65 | + "chrome/canary", | ||
66 | + "opera/12..latest", | ||
67 | + "opera/next", | ||
68 | + "safari/5.1..latest", | ||
69 | + "ipad/6.0..latest", | ||
70 | + "iphone/6.0..latest", | ||
71 | + "android-browser/4.2..latest" | ||
72 | + ] | ||
73 | + }, | ||
74 | + "version": "1.1.11" | ||
75 | +} |
1 | +test |
1 | +# node-bytes | ||
2 | + | ||
3 | + Byte string parser / formatter. | ||
4 | + | ||
5 | +## Example: | ||
6 | + | ||
7 | +```js | ||
8 | +bytes('1kb') | ||
9 | +// => 1024 | ||
10 | + | ||
11 | +bytes('2mb') | ||
12 | +// => 2097152 | ||
13 | + | ||
14 | +bytes('1gb') | ||
15 | +// => 1073741824 | ||
16 | + | ||
17 | +bytes(1073741824) | ||
18 | +// => 1gb | ||
19 | +``` | ||
20 | + | ||
21 | +## Installation | ||
22 | + | ||
23 | +``` | ||
24 | +$ npm install bytes | ||
25 | +$ component install visionmedia/bytes.js | ||
26 | +``` | ||
27 | + | ||
28 | +## License | ||
29 | + | ||
30 | +(The MIT License) | ||
31 | + | ||
32 | +Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca> | ||
33 | + | ||
34 | +Permission is hereby granted, free of charge, to any person obtaining | ||
35 | +a copy of this software and associated documentation files (the | ||
36 | +'Software'), to deal in the Software without restriction, including | ||
37 | +without limitation the rights to use, copy, modify, merge, publish, | ||
38 | +distribute, sublicense, and/or sell copies of the Software, and to | ||
39 | +permit persons to whom the Software is furnished to do so, subject to | ||
40 | +the following conditions: | ||
41 | + | ||
42 | +The above copyright notice and this permission notice shall be | ||
43 | +included in all copies or substantial portions of the Software. | ||
44 | + | ||
45 | +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, | ||
46 | +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
47 | +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
48 | +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
49 | +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
50 | +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
51 | +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
1 | + | ||
2 | +/** | ||
3 | + * Parse byte `size` string. | ||
4 | + * | ||
5 | + * @param {String} size | ||
6 | + * @return {Number} | ||
7 | + * @api public | ||
8 | + */ | ||
9 | + | ||
10 | +module.exports = function(size) { | ||
11 | + if ('number' == typeof size) return convert(size); | ||
12 | + var parts = size.match(/^(\d+(?:\.\d+)?) *(kb|mb|gb)$/) | ||
13 | + , n = parseFloat(parts[1]) | ||
14 | + , type = parts[2]; | ||
15 | + | ||
16 | + var map = { | ||
17 | + kb: 1 << 10 | ||
18 | + , mb: 1 << 20 | ||
19 | + , gb: 1 << 30 | ||
20 | + }; | ||
21 | + | ||
22 | + return map[type] * n; | ||
23 | +}; | ||
24 | + | ||
25 | +/** | ||
26 | + * convert bytes into string. | ||
27 | + * | ||
28 | + * @param {Number} b - bytes to convert | ||
29 | + * @return {String}i | ||
30 | + * @api public | ||
31 | + */ | ||
32 | + | ||
33 | +function convert (b) { | ||
34 | + var gb = 1 << 30, mb = 1 << 20, kb = 1 << 10; | ||
35 | + if (b >= gb) return (Math.round(b / gb * 100) / 100) + 'gb'; | ||
36 | + if (b >= mb) return (Math.round(b / mb * 100) / 100) + 'mb'; | ||
37 | + if (b >= kb) return (Math.round(b / kb * 100) / 100) + 'kb'; | ||
38 | + return b; | ||
39 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +{ | ||
2 | + "_from": "bytes@0.1.0", | ||
3 | + "_id": "bytes@0.1.0", | ||
4 | + "_inBundle": false, | ||
5 | + "_integrity": "sha1-xXSBIigSbWNp0VdpJahXnbP45aI=", | ||
6 | + "_location": "/bytes", | ||
7 | + "_phantomChildren": {}, | ||
8 | + "_requested": { | ||
9 | + "type": "version", | ||
10 | + "registry": true, | ||
11 | + "raw": "bytes@0.1.0", | ||
12 | + "name": "bytes", | ||
13 | + "escapedName": "bytes", | ||
14 | + "rawSpec": "0.1.0", | ||
15 | + "saveSpec": null, | ||
16 | + "fetchSpec": "0.1.0" | ||
17 | + }, | ||
18 | + "_requiredBy": [ | ||
19 | + "/connect" | ||
20 | + ], | ||
21 | + "_resolved": "https://registry.npmjs.org/bytes/-/bytes-0.1.0.tgz", | ||
22 | + "_shasum": "c574812228126d6369d1576925a8579db3f8e5a2", | ||
23 | + "_spec": "bytes@0.1.0", | ||
24 | + "_where": "C:\\Users\\경훈\\Desktop\\nodejs-todo-list-master\\nodejs-todo-list-master\\node_modules\\connect", | ||
25 | + "author": { | ||
26 | + "name": "TJ Holowaychuk", | ||
27 | + "email": "tj@vision-media.ca", | ||
28 | + "url": "http://tjholowaychuk.com" | ||
29 | + }, | ||
30 | + "bundleDependencies": false, | ||
31 | + "component": { | ||
32 | + "scripts": { | ||
33 | + "bytes": "index.js" | ||
34 | + } | ||
35 | + }, | ||
36 | + "dependencies": {}, | ||
37 | + "deprecated": false, | ||
38 | + "description": "byte size string parser / serializer", | ||
39 | + "devDependencies": { | ||
40 | + "mocha": "*", | ||
41 | + "should": "*" | ||
42 | + }, | ||
43 | + "main": "index.js", | ||
44 | + "name": "bytes", | ||
45 | + "version": "0.1.0" | ||
46 | +} |
... | @@ -21,7 +21,7 @@ | ... | @@ -21,7 +21,7 @@ |
21 | "_resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", | 21 | "_resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", |
22 | "_shasum": "1b681c21ff84033c826543090689420d187151dc", | 22 | "_shasum": "1b681c21ff84033c826543090689420d187151dc", |
23 | "_spec": "caseless@~0.12.0", | 23 | "_spec": "caseless@~0.12.0", |
24 | - "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\request", | 24 | + "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\nodejs-todo-list-master\\node_modules\\request", |
25 | "author": { | 25 | "author": { |
26 | "name": "Mikeal Rogers", | 26 | "name": "Mikeal Rogers", |
27 | "email": "mikeal.rogers@gmail.com" | 27 | "email": "mikeal.rogers@gmail.com" | ... | ... |
... | @@ -22,7 +22,7 @@ | ... | @@ -22,7 +22,7 @@ |
22 | "_resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", | 22 | "_resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", |
23 | "_shasum": "c3d45a8b34fd730631a110a8a2520682b31d5a7f", | 23 | "_shasum": "c3d45a8b34fd730631a110a8a2520682b31d5a7f", |
24 | "_spec": "combined-stream@~1.0.6", | 24 | "_spec": "combined-stream@~1.0.6", |
25 | - "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\request", | 25 | + "_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\nodejs-todo-list-master\\node_modules\\request", |
26 | "author": { | 26 | "author": { |
27 | "name": "Felix Geisendörfer", | 27 | "name": "Felix Geisendörfer", |
28 | "email": "felix@debuggable.com", | 28 | "email": "felix@debuggable.com", | ... | ... |
1 | + | ||
2 | +0.6.1 / 2012-06-01 | ||
3 | +================== | ||
4 | + | ||
5 | + * Added: append (yes or no) on confirmation | ||
6 | + * Added: allow node.js v0.7.x | ||
7 | + | ||
8 | +0.6.0 / 2012-04-10 | ||
9 | +================== | ||
10 | + | ||
11 | + * Added `.prompt(obj, callback)` support. Closes #49 | ||
12 | + * Added default support to .choose(). Closes #41 | ||
13 | + * Fixed the choice example | ||
14 | + | ||
15 | +0.5.1 / 2011-12-20 | ||
16 | +================== | ||
17 | + | ||
18 | + * Fixed `password()` for recent nodes. Closes #36 | ||
19 | + | ||
20 | +0.5.0 / 2011-12-04 | ||
21 | +================== | ||
22 | + | ||
23 | + * Added sub-command option support [itay] | ||
24 | + | ||
25 | +0.4.3 / 2011-12-04 | ||
26 | +================== | ||
27 | + | ||
28 | + * Fixed custom help ordering. Closes #32 | ||
29 | + | ||
30 | +0.4.2 / 2011-11-24 | ||
31 | +================== | ||
32 | + | ||
33 | + * Added travis support | ||
34 | + * Fixed: line-buffered input automatically trimmed. Closes #31 | ||
35 | + | ||
36 | +0.4.1 / 2011-11-18 | ||
37 | +================== | ||
38 | + | ||
39 | + * Removed listening for "close" on --help | ||
40 | + | ||
41 | +0.4.0 / 2011-11-15 | ||
42 | +================== | ||
43 | + | ||
44 | + * Added support for `--`. Closes #24 | ||
45 | + | ||
46 | +0.3.3 / 2011-11-14 | ||
47 | +================== | ||
48 | + | ||
49 | + * Fixed: wait for close event when writing help info [Jerry Hamlet] | ||
50 | + | ||
51 | +0.3.2 / 2011-11-01 | ||
52 | +================== | ||
53 | + | ||
54 | + * Fixed long flag definitions with values [felixge] | ||
55 | + | ||
56 | +0.3.1 / 2011-10-31 | ||
57 | +================== | ||
58 | + | ||
59 | + * Changed `--version` short flag to `-V` from `-v` | ||
60 | + * Changed `.version()` so it's configurable [felixge] | ||
61 | + | ||
62 | +0.3.0 / 2011-10-31 | ||
63 | +================== | ||
64 | + | ||
65 | + * Added support for long flags only. Closes #18 | ||
66 | + | ||
67 | +0.2.1 / 2011-10-24 | ||
68 | +================== | ||
69 | + | ||
70 | + * "node": ">= 0.4.x < 0.7.0". Closes #20 | ||
71 | + | ||
72 | +0.2.0 / 2011-09-26 | ||
73 | +================== | ||
74 | + | ||
75 | + * Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs] | ||
76 | + | ||
77 | +0.1.0 / 2011-08-24 | ||
78 | +================== | ||
79 | + | ||
80 | + * Added support for custom `--help` output | ||
81 | + | ||
82 | +0.0.5 / 2011-08-18 | ||
83 | +================== | ||
84 | + | ||
85 | + * Changed: when the user enters nothing prompt for password again | ||
86 | + * Fixed issue with passwords beginning with numbers [NuckChorris] | ||
87 | + | ||
88 | +0.0.4 / 2011-08-15 | ||
89 | +================== | ||
90 | + | ||
91 | + * Fixed `Commander#args` | ||
92 | + | ||
93 | +0.0.3 / 2011-08-15 | ||
94 | +================== | ||
95 | + | ||
96 | + * Added default option value support | ||
97 | + | ||
98 | +0.0.2 / 2011-08-15 | ||
99 | +================== | ||
100 | + | ||
101 | + * Added mask support to `Command#password(str[, mask], fn)` | ||
102 | + * Added `Command#password(str, fn)` | ||
103 | + | ||
104 | +0.0.1 / 2010-01-03 | ||
105 | +================== | ||
106 | + | ||
107 | + * Initial release |
1 | +# Commander.js | ||
2 | + | ||
3 | + The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander). | ||
4 | + | ||
5 | + [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js) | ||
6 | + | ||
7 | +## Installation | ||
8 | + | ||
9 | + $ npm install commander | ||
10 | + | ||
11 | +## Option parsing | ||
12 | + | ||
13 | + Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options. | ||
14 | + | ||
15 | +```js | ||
16 | +#!/usr/bin/env node | ||
17 | + | ||
18 | +/** | ||
19 | + * Module dependencies. | ||
20 | + */ | ||
21 | + | ||
22 | +var program = require('commander'); | ||
23 | + | ||
24 | +program | ||
25 | + .version('0.0.1') | ||
26 | + .option('-p, --peppers', 'Add peppers') | ||
27 | + .option('-P, --pineapple', 'Add pineapple') | ||
28 | + .option('-b, --bbq', 'Add bbq sauce') | ||
29 | + .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble') | ||
30 | + .parse(process.argv); | ||
31 | + | ||
32 | +console.log('you ordered a pizza with:'); | ||
33 | +if (program.peppers) console.log(' - peppers'); | ||
34 | +if (program.pineapple) console.log(' - pineappe'); | ||
35 | +if (program.bbq) console.log(' - bbq'); | ||
36 | +console.log(' - %s cheese', program.cheese); | ||
37 | +``` | ||
38 | + | ||
39 | + Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc. | ||
40 | + | ||
41 | +## Automated --help | ||
42 | + | ||
43 | + The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free: | ||
44 | + | ||
45 | +``` | ||
46 | + $ ./examples/pizza --help | ||
47 | + | ||
48 | + Usage: pizza [options] | ||
49 | + | ||
50 | + Options: | ||
51 | + | ||
52 | + -V, --version output the version number | ||
53 | + -p, --peppers Add peppers | ||
54 | + -P, --pineapple Add pineappe | ||
55 | + -b, --bbq Add bbq sauce | ||
56 | + -c, --cheese <type> Add the specified type of cheese [marble] | ||
57 | + -h, --help output usage information | ||
58 | + | ||
59 | +``` | ||
60 | + | ||
61 | +## Coercion | ||
62 | + | ||
63 | +```js | ||
64 | +function range(val) { | ||
65 | + return val.split('..').map(Number); | ||
66 | +} | ||
67 | + | ||
68 | +function list(val) { | ||
69 | + return val.split(','); | ||
70 | +} | ||
71 | + | ||
72 | +program | ||
73 | + .version('0.0.1') | ||
74 | + .usage('[options] <file ...>') | ||
75 | + .option('-i, --integer <n>', 'An integer argument', parseInt) | ||
76 | + .option('-f, --float <n>', 'A float argument', parseFloat) | ||
77 | + .option('-r, --range <a>..<b>', 'A range', range) | ||
78 | + .option('-l, --list <items>', 'A list', list) | ||
79 | + .option('-o, --optional [value]', 'An optional value') | ||
80 | + .parse(process.argv); | ||
81 | + | ||
82 | +console.log(' int: %j', program.integer); | ||
83 | +console.log(' float: %j', program.float); | ||
84 | +console.log(' optional: %j', program.optional); | ||
85 | +program.range = program.range || []; | ||
86 | +console.log(' range: %j..%j', program.range[0], program.range[1]); | ||
87 | +console.log(' list: %j', program.list); | ||
88 | +console.log(' args: %j', program.args); | ||
89 | +``` | ||
90 | + | ||
91 | +## Custom help | ||
92 | + | ||
93 | + You can display arbitrary `-h, --help` information | ||
94 | + by listening for "--help". Commander will automatically | ||
95 | + exit once you are done so that the remainder of your program | ||
96 | + does not execute causing undesired behaviours, for example | ||
97 | + in the following executable "stuff" will not output when | ||
98 | + `--help` is used. | ||
99 | + | ||
100 | +```js | ||
101 | +#!/usr/bin/env node | ||
102 | + | ||
103 | +/** | ||
104 | + * Module dependencies. | ||
105 | + */ | ||
106 | + | ||
107 | +var program = require('../'); | ||
108 | + | ||
109 | +function list(val) { | ||
110 | + return val.split(',').map(Number); | ||
111 | +} | ||
112 | + | ||
113 | +program | ||
114 | + .version('0.0.1') | ||
115 | + .option('-f, --foo', 'enable some foo') | ||
116 | + .option('-b, --bar', 'enable some bar') | ||
117 | + .option('-B, --baz', 'enable some baz'); | ||
118 | + | ||
119 | +// must be before .parse() since | ||
120 | +// node's emit() is immediate | ||
121 | + | ||
122 | +program.on('--help', function(){ | ||
123 | + console.log(' Examples:'); | ||
124 | + console.log(''); | ||
125 | + console.log(' $ custom-help --help'); | ||
126 | + console.log(' $ custom-help -h'); | ||
127 | + console.log(''); | ||
128 | +}); | ||
129 | + | ||
130 | +program.parse(process.argv); | ||
131 | + | ||
132 | +console.log('stuff'); | ||
133 | +``` | ||
134 | + | ||
135 | +yielding the following help output: | ||
136 | + | ||
137 | +``` | ||
138 | + | ||
139 | +Usage: custom-help [options] | ||
140 | + | ||
141 | +Options: | ||
142 | + | ||
143 | + -h, --help output usage information | ||
144 | + -V, --version output the version number | ||
145 | + -f, --foo enable some foo | ||
146 | + -b, --bar enable some bar | ||
147 | + -B, --baz enable some baz | ||
148 | + | ||
149 | +Examples: | ||
150 | + | ||
151 | + $ custom-help --help | ||
152 | + $ custom-help -h | ||
153 | + | ||
154 | +``` | ||
155 | + | ||
156 | +## .prompt(msg, fn) | ||
157 | + | ||
158 | + Single-line prompt: | ||
159 | + | ||
160 | +```js | ||
161 | +program.prompt('name: ', function(name){ | ||
162 | + console.log('hi %s', name); | ||
163 | +}); | ||
164 | +``` | ||
165 | + | ||
166 | + Multi-line prompt: | ||
167 | + | ||
168 | +```js | ||
169 | +program.prompt('description:', function(name){ | ||
170 | + console.log('hi %s', name); | ||
171 | +}); | ||
172 | +``` | ||
173 | + | ||
174 | + Coercion: | ||
175 | + | ||
176 | +```js | ||
177 | +program.prompt('Age: ', Number, function(age){ | ||
178 | + console.log('age: %j', age); | ||
179 | +}); | ||
180 | +``` | ||
181 | + | ||
182 | +```js | ||
183 | +program.prompt('Birthdate: ', Date, function(date){ | ||
184 | + console.log('date: %s', date); | ||
185 | +}); | ||
186 | +``` | ||
187 | + | ||
188 | +## .password(msg[, mask], fn) | ||
189 | + | ||
190 | +Prompt for password without echoing: | ||
191 | + | ||
192 | +```js | ||
193 | +program.password('Password: ', function(pass){ | ||
194 | + console.log('got "%s"', pass); | ||
195 | + process.stdin.destroy(); | ||
196 | +}); | ||
197 | +``` | ||
198 | + | ||
199 | +Prompt for password with mask char "*": | ||
200 | + | ||
201 | +```js | ||
202 | +program.password('Password: ', '*', function(pass){ | ||
203 | + console.log('got "%s"', pass); | ||
204 | + process.stdin.destroy(); | ||
205 | +}); | ||
206 | +``` | ||
207 | + | ||
208 | +## .confirm(msg, fn) | ||
209 | + | ||
210 | + Confirm with the given `msg`: | ||
211 | + | ||
212 | +```js | ||
213 | +program.confirm('continue? ', function(ok){ | ||
214 | + console.log(' got %j', ok); | ||
215 | +}); | ||
216 | +``` | ||
217 | + | ||
218 | +## .choose(list, fn) | ||
219 | + | ||
220 | + Let the user choose from a `list`: | ||
221 | + | ||
222 | +```js | ||
223 | +var list = ['tobi', 'loki', 'jane', 'manny', 'luna']; | ||
224 | + | ||
225 | +console.log('Choose the coolest pet:'); | ||
226 | +program.choose(list, function(i){ | ||
227 | + console.log('you chose %d "%s"', i, list[i]); | ||
228 | +}); | ||
229 | +``` | ||
230 | + | ||
231 | +## Links | ||
232 | + | ||
233 | + - [API documentation](http://visionmedia.github.com/commander.js/) | ||
234 | + - [ascii tables](https://github.com/LearnBoost/cli-table) | ||
235 | + - [progress bars](https://github.com/visionmedia/node-progress) | ||
236 | + - [more progress bars](https://github.com/substack/node-multimeter) | ||
237 | + - [examples](https://github.com/visionmedia/commander.js/tree/master/examples) | ||
238 | + | ||
239 | +## License | ||
240 | + | ||
241 | +(The MIT License) | ||
242 | + | ||
243 | +Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca> | ||
244 | + | ||
245 | +Permission is hereby granted, free of charge, to any person obtaining | ||
246 | +a copy of this software and associated documentation files (the | ||
247 | +'Software'), to deal in the Software without restriction, including | ||
248 | +without limitation the rights to use, copy, modify, merge, publish, | ||
249 | +distribute, sublicense, and/or sell copies of the Software, and to | ||
250 | +permit persons to whom the Software is furnished to do so, subject to | ||
251 | +the following conditions: | ||
252 | + | ||
253 | +The above copyright notice and this permission notice shall be | ||
254 | +included in all copies or substantial portions of the Software. | ||
255 | + | ||
256 | +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, | ||
257 | +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
258 | +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
259 | +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
260 | +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
261 | +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
262 | +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +{ | ||
2 | + "_from": "commander@0.6.1", | ||
3 | + "_id": "commander@0.6.1", | ||
4 | + "_inBundle": false, | ||
5 | + "_integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", | ||
6 | + "_location": "/commander", | ||
7 | + "_phantomChildren": {}, | ||
8 | + "_requested": { | ||
9 | + "type": "version", | ||
10 | + "registry": true, | ||
11 | + "raw": "commander@0.6.1", | ||
12 | + "name": "commander", | ||
13 | + "escapedName": "commander", | ||
14 | + "rawSpec": "0.6.1", | ||
15 | + "saveSpec": null, | ||
16 | + "fetchSpec": "0.6.1" | ||
17 | + }, | ||
18 | + "_requiredBy": [ | ||
19 | + "/express" | ||
20 | + ], | ||
21 | + "_resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", | ||
22 | + "_shasum": "fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06", | ||
23 | + "_spec": "commander@0.6.1", | ||
24 | + "_where": "C:\\Users\\경훈\\Desktop\\nodejs-todo-list-master\\nodejs-todo-list-master\\node_modules\\express", | ||
25 | + "author": { | ||
26 | + "name": "TJ Holowaychuk", | ||
27 | + "email": "tj@vision-media.ca" | ||
28 | + }, | ||
29 | + "bugs": { | ||
30 | + "url": "https://github.com/visionmedia/commander.js/issues" | ||
31 | + }, | ||
32 | + "bundleDependencies": false, | ||
33 | + "dependencies": {}, | ||
34 | + "deprecated": false, | ||
35 | + "description": "the complete solution for node.js command-line programs", | ||
36 | + "devDependencies": { | ||
37 | + "should": ">= 0.0.1" | ||
38 | + }, | ||
39 | + "engines": { | ||
40 | + "node": ">= 0.4.x" | ||
41 | + }, | ||
42 | + "homepage": "https://github.com/visionmedia/commander.js#readme", | ||
43 | + "keywords": [ | ||
44 | + "command", | ||
45 | + "option", | ||
46 | + "parser", | ||
47 | + "prompt", | ||
48 | + "stdin" | ||
49 | + ], | ||
50 | + "main": "index", | ||
51 | + "name": "commander", | ||
52 | + "repository": { | ||
53 | + "type": "git", | ||
54 | + "url": "git+https://github.com/visionmedia/commander.js.git" | ||
55 | + }, | ||
56 | + "scripts": { | ||
57 | + "test": "make test" | ||
58 | + }, | ||
59 | + "version": "0.6.1" | ||
60 | +} |
1 | +This software is released under the MIT license: | ||
2 | + | ||
3 | +Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
4 | +this software and associated documentation files (the "Software"), to deal in | ||
5 | +the Software without restriction, including without limitation the rights to | ||
6 | +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
7 | +the Software, and to permit persons to whom the Software is furnished to do so, | ||
8 | +subject to the following conditions: | ||
9 | + | ||
10 | +The above copyright notice and this permission notice shall be included in all | ||
11 | +copies or substantial portions of the Software. | ||
12 | + | ||
13 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
15 | +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
16 | +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
17 | +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
18 | +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
1 | +concat-map | ||
2 | +========== | ||
3 | + | ||
4 | +Concatenative mapdashery. | ||
5 | + | ||
6 | +[![browser support](http://ci.testling.com/substack/node-concat-map.png)](http://ci.testling.com/substack/node-concat-map) | ||
7 | + | ||
8 | +[![build status](https://secure.travis-ci.org/substack/node-concat-map.png)](http://travis-ci.org/substack/node-concat-map) | ||
9 | + | ||
10 | +example | ||
11 | +======= | ||
12 | + | ||
13 | +``` js | ||
14 | +var concatMap = require('concat-map'); | ||
15 | +var xs = [ 1, 2, 3, 4, 5, 6 ]; | ||
16 | +var ys = concatMap(xs, function (x) { | ||
17 | + return x % 2 ? [ x - 0.1, x, x + 0.1 ] : []; | ||
18 | +}); | ||
19 | +console.dir(ys); | ||
20 | +``` | ||
21 | + | ||
22 | +*** | ||
23 | + | ||
24 | +``` | ||
25 | +[ 0.9, 1, 1.1, 2.9, 3, 3.1, 4.9, 5, 5.1 ] | ||
26 | +``` | ||
27 | + | ||
28 | +methods | ||
29 | +======= | ||
30 | + | ||
31 | +``` js | ||
32 | +var concatMap = require('concat-map') | ||
33 | +``` | ||
34 | + | ||
35 | +concatMap(xs, fn) | ||
36 | +----------------- | ||
37 | + | ||
38 | +Return an array of concatenated elements by calling `fn(x, i)` for each element | ||
39 | +`x` and each index `i` in the array `xs`. | ||
40 | + | ||
41 | +When `fn(x, i)` returns an array, its result will be concatenated with the | ||
42 | +result array. If `fn(x, i)` returns anything else, that value will be pushed | ||
43 | +onto the end of the result array. | ||
44 | + | ||
45 | +install | ||
46 | +======= | ||
47 | + | ||
48 | +With [npm](http://npmjs.org) do: | ||
49 | + | ||
50 | +``` | ||
51 | +npm install concat-map | ||
52 | +``` | ||
53 | + | ||
54 | +license | ||
55 | +======= | ||
56 | + | ||
57 | +MIT | ||
58 | + | ||
59 | +notes | ||
60 | +===== | ||
61 | + | ||
62 | +This module was written while sitting high above the ground in a tree. |
1 | +module.exports = function (xs, fn) { | ||
2 | + var res = []; | ||
3 | + for (var i = 0; i < xs.length; i++) { | ||
4 | + var x = fn(xs[i], i); | ||
5 | + if (isArray(x)) res.push.apply(res, x); | ||
6 | + else res.push(x); | ||
7 | + } | ||
8 | + return res; | ||
9 | +}; | ||
10 | + | ||
11 | +var isArray = Array.isArray || function (xs) { | ||
12 | + return Object.prototype.toString.call(xs) === '[object Array]'; | ||
13 | +}; |
1 | +{ | ||
2 | + "_from": "concat-map@0.0.1", | ||
3 | + "_id": "concat-map@0.0.1", | ||
4 | + "_inBundle": false, | ||
5 | + "_integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", | ||
6 | + "_location": "/concat-map", | ||
7 | + "_phantomChildren": {}, | ||
8 | + "_requested": { | ||
9 | + "type": "version", | ||
10 | + "registry": true, | ||
11 | + "raw": "concat-map@0.0.1", | ||
12 | + "name": "concat-map", | ||
13 | + "escapedName": "concat-map", | ||
14 | + "rawSpec": "0.0.1", | ||
15 | + "saveSpec": null, | ||
16 | + "fetchSpec": "0.0.1" | ||
17 | + }, | ||
18 | + "_requiredBy": [ | ||
19 | + "/brace-expansion" | ||
20 | + ], | ||
21 | + "_resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", | ||
22 | + "_shasum": "d8a96bd77fd68df7793a73036a3ba0d5405d477b", | ||
23 | + "_spec": "concat-map@0.0.1", | ||
24 | + "_where": "C:\\Users\\경훈\\Desktop\\nodejs-todo-list-master\\nodejs-todo-list-master\\node_modules\\brace-expansion", | ||
25 | + "author": { | ||
26 | + "name": "James Halliday", | ||
27 | + "email": "mail@substack.net", | ||
28 | + "url": "http://substack.net" | ||
29 | + }, | ||
30 | + "bugs": { | ||
31 | + "url": "https://github.com/substack/node-concat-map/issues" | ||
32 | + }, | ||
33 | + "bundleDependencies": false, | ||
34 | + "deprecated": false, | ||
35 | + "description": "concatenative mapdashery", | ||
36 | + "devDependencies": { | ||
37 | + "tape": "~2.4.0" | ||
38 | + }, | ||
39 | + "directories": { | ||
40 | + "example": "example", | ||
41 | + "test": "test" | ||
42 | + }, | ||
43 | + "homepage": "https://github.com/substack/node-concat-map#readme", | ||
44 | + "keywords": [ | ||
45 | + "concat", | ||
46 | + "concatMap", | ||
47 | + "map", | ||
48 | + "functional", | ||
49 | + "higher-order" | ||
50 | + ], | ||
51 | + "license": "MIT", | ||
52 | + "main": "index.js", | ||
53 | + "name": "concat-map", | ||
54 | + "repository": { | ||
55 | + "type": "git", | ||
56 | + "url": "git://github.com/substack/node-concat-map.git" | ||
57 | + }, | ||
58 | + "scripts": { | ||
59 | + "test": "tape test/*.js" | ||
60 | + }, | ||
61 | + "testling": { | ||
62 | + "files": "test/*.js", | ||
63 | + "browsers": { | ||
64 | + "ie": [ | ||
65 | + 6, | ||
66 | + 7, | ||
67 | + 8, | ||
68 | + 9 | ||
69 | + ], | ||
70 | + "ff": [ | ||
71 | + 3.5, | ||
72 | + 10, | ||
73 | + 15 | ||
74 | + ], | ||
75 | + "chrome": [ | ||
76 | + 10, | ||
77 | + 22 | ||
78 | + ], | ||
79 | + "safari": [ | ||
80 | + 5.1 | ||
81 | + ], | ||
82 | + "opera": [ | ||
83 | + 12 | ||
84 | + ] | ||
85 | + } | ||
86 | + }, | ||
87 | + "version": "0.0.1" | ||
88 | +} |
1 | +var concatMap = require('../'); | ||
2 | +var test = require('tape'); | ||
3 | + | ||
4 | +test('empty or not', function (t) { | ||
5 | + var xs = [ 1, 2, 3, 4, 5, 6 ]; | ||
6 | + var ixes = []; | ||
7 | + var ys = concatMap(xs, function (x, ix) { | ||
8 | + ixes.push(ix); | ||
9 | + return x % 2 ? [ x - 0.1, x, x + 0.1 ] : []; | ||
10 | + }); | ||
11 | + t.same(ys, [ 0.9, 1, 1.1, 2.9, 3, 3.1, 4.9, 5, 5.1 ]); | ||
12 | + t.same(ixes, [ 0, 1, 2, 3, 4, 5 ]); | ||
13 | + t.end(); | ||
14 | +}); | ||
15 | + | ||
16 | +test('always something', function (t) { | ||
17 | + var xs = [ 'a', 'b', 'c', 'd' ]; | ||
18 | + var ys = concatMap(xs, function (x) { | ||
19 | + return x === 'b' ? [ 'B', 'B', 'B' ] : [ x ]; | ||
20 | + }); | ||
21 | + t.same(ys, [ 'a', 'B', 'B', 'B', 'c', 'd' ]); | ||
22 | + t.end(); | ||
23 | +}); | ||
24 | + | ||
25 | +test('scalars', function (t) { | ||
26 | + var xs = [ 'a', 'b', 'c', 'd' ]; | ||
27 | + var ys = concatMap(xs, function (x) { | ||
28 | + return x === 'b' ? [ 'B', 'B', 'B' ] : x; | ||
29 | + }); | ||
30 | + t.same(ys, [ 'a', 'B', 'B', 'B', 'c', 'd' ]); | ||
31 | + t.end(); | ||
32 | +}); | ||
33 | + | ||
34 | +test('undefs', function (t) { | ||
35 | + var xs = [ 'a', 'b', 'c', 'd' ]; | ||
36 | + var ys = concatMap(xs, function () {}); | ||
37 | + t.same(ys, [ undefined, undefined, undefined, undefined ]); | ||
38 | + t.end(); | ||
39 | +}); |
1 | +(The MIT License) | ||
2 | + | ||
3 | +Copyright (c) 2010 Sencha Inc. | ||
4 | +Copyright (c) 2011 LearnBoost | ||
5 | +Copyright (c) 2011 TJ Holowaychuk | ||
6 | + | ||
7 | +Permission is hereby granted, free of charge, to any person obtaining | ||
8 | +a copy of this software and associated documentation files (the | ||
9 | +'Software'), to deal in the Software without restriction, including | ||
10 | +without limitation the rights to use, copy, modify, merge, publish, | ||
11 | +distribute, sublicense, and/or sell copies of the Software, and to | ||
12 | +permit persons to whom the Software is furnished to do so, subject to | ||
13 | +the following conditions: | ||
14 | + | ||
15 | +The above copyright notice and this permission notice shall be | ||
16 | +included in all copies or substantial portions of the Software. | ||
17 | + | ||
18 | +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, | ||
19 | +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
20 | +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
21 | +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
22 | +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
23 | +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
24 | +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +[![build status](https://secure.travis-ci.org/senchalabs/connect.png)](http://travis-ci.org/senchalabs/connect) | ||
2 | +# Connect | ||
3 | + | ||
4 | + Connect is an extensible HTTP server framework for [node](http://nodejs.org), providing high performance "plugins" known as _middleware_. | ||
5 | + | ||
6 | + Connect is bundled with over _20_ commonly used middleware, including | ||
7 | + a logger, session support, cookie parser, and [more](http://senchalabs.github.com/connect). Be sure to view the 2.x [documentation](http://senchalabs.github.com/connect/). | ||
8 | + | ||
9 | +```js | ||
10 | +var connect = require('connect') | ||
11 | + , http = require('http'); | ||
12 | + | ||
13 | +var app = connect() | ||
14 | + .use(connect.favicon()) | ||
15 | + .use(connect.logger('dev')) | ||
16 | + .use(connect.static('public')) | ||
17 | + .use(connect.directory('public')) | ||
18 | + .use(connect.cookieParser()) | ||
19 | + .use(connect.session({ secret: 'my secret here' })) | ||
20 | + .use(function(req, res){ | ||
21 | + res.end('Hello from Connect!\n'); | ||
22 | + }); | ||
23 | + | ||
24 | +http.createServer(app).listen(3000); | ||
25 | +``` | ||
26 | + | ||
27 | +## Middleware | ||
28 | + | ||
29 | + - [csrf](http://www.senchalabs.org/connect/csrf.html) | ||
30 | + - [basicAuth](http://www.senchalabs.org/connect/basicAuth.html) | ||
31 | + - [bodyParser](http://www.senchalabs.org/connect/bodyParser.html) | ||
32 | + - [json](http://www.senchalabs.org/connect/json.html) | ||
33 | + - [multipart](http://www.senchalabs.org/connect/multipart.html) | ||
34 | + - [urlencoded](http://www.senchalabs.org/connect/urlencoded.html) | ||
35 | + - [cookieParser](http://www.senchalabs.org/connect/cookieParser.html) | ||
36 | + - [directory](http://www.senchalabs.org/connect/directory.html) | ||
37 | + - [compress](http://www.senchalabs.org/connect/compress.html) | ||
38 | + - [errorHandler](http://www.senchalabs.org/connect/errorHandler.html) | ||
39 | + - [favicon](http://www.senchalabs.org/connect/favicon.html) | ||
40 | + - [limit](http://www.senchalabs.org/connect/limit.html) | ||
41 | + - [logger](http://www.senchalabs.org/connect/logger.html) | ||
42 | + - [methodOverride](http://www.senchalabs.org/connect/methodOverride.html) | ||
43 | + - [query](http://www.senchalabs.org/connect/query.html) | ||
44 | + - [responseTime](http://www.senchalabs.org/connect/responseTime.html) | ||
45 | + - [session](http://www.senchalabs.org/connect/session.html) | ||
46 | + - [static](http://www.senchalabs.org/connect/static.html) | ||
47 | + - [staticCache](http://www.senchalabs.org/connect/staticCache.html) | ||
48 | + - [vhost](http://www.senchalabs.org/connect/vhost.html) | ||
49 | + - [subdomains](http://www.senchalabs.org/connect/subdomains.html) | ||
50 | + - [cookieSession](http://www.senchalabs.org/connect/cookieSession.html) | ||
51 | + | ||
52 | +## Running Tests | ||
53 | + | ||
54 | +first: | ||
55 | + | ||
56 | + $ npm install -d | ||
57 | + | ||
58 | +then: | ||
59 | + | ||
60 | + $ make test | ||
61 | + | ||
62 | +## Authors | ||
63 | + | ||
64 | + Below is the output from [git-summary](http://github.com/visionmedia/git-extras). | ||
65 | + | ||
66 | + | ||
67 | + project: connect | ||
68 | + commits: 2033 | ||
69 | + active : 301 days | ||
70 | + files : 171 | ||
71 | + authors: | ||
72 | + 1414 Tj Holowaychuk 69.6% | ||
73 | + 298 visionmedia 14.7% | ||
74 | + 191 Tim Caswell 9.4% | ||
75 | + 51 TJ Holowaychuk 2.5% | ||
76 | + 10 Ryan Olds 0.5% | ||
77 | + 8 Astro 0.4% | ||
78 | + 5 Nathan Rajlich 0.2% | ||
79 | + 5 Jakub Nešetřil 0.2% | ||
80 | + 3 Daniel Dickison 0.1% | ||
81 | + 3 David Rio Deiros 0.1% | ||
82 | + 3 Alexander Simmerl 0.1% | ||
83 | + 3 Andreas Lind Petersen 0.1% | ||
84 | + 2 Aaron Heckmann 0.1% | ||
85 | + 2 Jacques Crocker 0.1% | ||
86 | + 2 Fabian Jakobs 0.1% | ||
87 | + 2 Brian J Brennan 0.1% | ||
88 | + 2 Adam Malcontenti-Wilson 0.1% | ||
89 | + 2 Glen Mailer 0.1% | ||
90 | + 2 James Campos 0.1% | ||
91 | + 1 Trent Mick 0.0% | ||
92 | + 1 Troy Kruthoff 0.0% | ||
93 | + 1 Wei Zhu 0.0% | ||
94 | + 1 comerc 0.0% | ||
95 | + 1 darobin 0.0% | ||
96 | + 1 nateps 0.0% | ||
97 | + 1 Marco Sanson 0.0% | ||
98 | + 1 Arthur Taylor 0.0% | ||
99 | + 1 Aseem Kishore 0.0% | ||
100 | + 1 Bart Teeuwisse 0.0% | ||
101 | + 1 Cameron Howey 0.0% | ||
102 | + 1 Chad Weider 0.0% | ||
103 | + 1 Craig Barnes 0.0% | ||
104 | + 1 Eran Hammer-Lahav 0.0% | ||
105 | + 1 Gregory McWhirter 0.0% | ||
106 | + 1 Guillermo Rauch 0.0% | ||
107 | + 1 Jae Kwon 0.0% | ||
108 | + 1 Jakub Nesetril 0.0% | ||
109 | + 1 Joshua Peek 0.0% | ||
110 | + 1 Jxck 0.0% | ||
111 | + 1 AJ ONeal 0.0% | ||
112 | + 1 Michael Hemesath 0.0% | ||
113 | + 1 Morten Siebuhr 0.0% | ||
114 | + 1 Samori Gorse 0.0% | ||
115 | + 1 Tom Jensen 0.0% | ||
116 | + | ||
117 | +## Node Compatibility | ||
118 | + | ||
119 | + Connect `< 1.x` is compatible with node 0.2.x | ||
120 | + | ||
121 | + | ||
122 | + Connect `1.x` is compatible with node 0.4.x | ||
123 | + | ||
124 | + | ||
125 | + Connect (_master_) `2.x` is compatible with node 0.6.x | ||
126 | + | ||
127 | +## CLA | ||
128 | + | ||
129 | + [http://sencha.com/cla](http://sencha.com/cla) | ||
130 | + | ||
131 | +## License | ||
132 | + | ||
133 | +View the [LICENSE](https://github.com/senchalabs/connect/blob/master/LICENSE) file. The [Silk](http://www.famfamfam.com/lab/icons/silk/) icons used by the `directory` middleware created by/copyright of [FAMFAMFAM](http://www.famfamfam.com/). |
1 | + | ||
2 | +/*! | ||
3 | + * Connect - Cache | ||
4 | + * Copyright(c) 2011 Sencha Inc. | ||
5 | + * MIT Licensed | ||
6 | + */ | ||
7 | + | ||
8 | +/** | ||
9 | + * Expose `Cache`. | ||
10 | + */ | ||
11 | + | ||
12 | +module.exports = Cache; | ||
13 | + | ||
14 | +/** | ||
15 | + * LRU cache store. | ||
16 | + * | ||
17 | + * @param {Number} limit | ||
18 | + * @api private | ||
19 | + */ | ||
20 | + | ||
21 | +function Cache(limit) { | ||
22 | + this.store = {}; | ||
23 | + this.keys = []; | ||
24 | + this.limit = limit; | ||
25 | +} | ||
26 | + | ||
27 | +/** | ||
28 | + * Touch `key`, promoting the object. | ||
29 | + * | ||
30 | + * @param {String} key | ||
31 | + * @param {Number} i | ||
32 | + * @api private | ||
33 | + */ | ||
34 | + | ||
35 | +Cache.prototype.touch = function(key, i){ | ||
36 | + this.keys.splice(i,1); | ||
37 | + this.keys.push(key); | ||
38 | +}; | ||
39 | + | ||
40 | +/** | ||
41 | + * Remove `key`. | ||
42 | + * | ||
43 | + * @param {String} key | ||
44 | + * @api private | ||
45 | + */ | ||
46 | + | ||
47 | +Cache.prototype.remove = function(key){ | ||
48 | + delete this.store[key]; | ||
49 | +}; | ||
50 | + | ||
51 | +/** | ||
52 | + * Get the object stored for `key`. | ||
53 | + * | ||
54 | + * @param {String} key | ||
55 | + * @return {Array} | ||
56 | + * @api private | ||
57 | + */ | ||
58 | + | ||
59 | +Cache.prototype.get = function(key){ | ||
60 | + return this.store[key]; | ||
61 | +}; | ||
62 | + | ||
63 | +/** | ||
64 | + * Add a cache `key`. | ||
65 | + * | ||
66 | + * @param {String} key | ||
67 | + * @return {Array} | ||
68 | + * @api private | ||
69 | + */ | ||
70 | + | ||
71 | +Cache.prototype.add = function(key){ | ||
72 | + // initialize store | ||
73 | + var len = this.keys.push(key); | ||
74 | + | ||
75 | + // limit reached, invalidate LRU | ||
76 | + if (len > this.limit) this.remove(this.keys.shift()); | ||
77 | + | ||
78 | + var arr = this.store[key] = []; | ||
79 | + arr.createdAt = new Date; | ||
80 | + return arr; | ||
81 | +}; |
1 | + | ||
2 | +/*! | ||
3 | + * Connect | ||
4 | + * Copyright(c) 2010 Sencha Inc. | ||
5 | + * Copyright(c) 2011 TJ Holowaychuk | ||
6 | + * MIT Licensed | ||
7 | + */ | ||
8 | + | ||
9 | +/** | ||
10 | + * Module dependencies. | ||
11 | + */ | ||
12 | + | ||
13 | +var EventEmitter = require('events').EventEmitter | ||
14 | + , proto = require('./proto') | ||
15 | + , utils = require('./utils') | ||
16 | + , path = require('path') | ||
17 | + , basename = path.basename | ||
18 | + , fs = require('fs'); | ||
19 | + | ||
20 | +// node patches | ||
21 | + | ||
22 | +require('./patch'); | ||
23 | + | ||
24 | +// expose createServer() as the module | ||
25 | + | ||
26 | +exports = module.exports = createServer; | ||
27 | + | ||
28 | +/** | ||
29 | + * Framework version. | ||
30 | + */ | ||
31 | + | ||
32 | +exports.version = '2.6.1'; | ||
33 | + | ||
34 | +/** | ||
35 | + * Expose mime module. | ||
36 | + */ | ||
37 | + | ||
38 | +exports.mime = require('./middleware/static').mime; | ||
39 | + | ||
40 | +/** | ||
41 | + * Expose the prototype. | ||
42 | + */ | ||
43 | + | ||
44 | +exports.proto = proto; | ||
45 | + | ||
46 | +/** | ||
47 | + * Auto-load middleware getters. | ||
48 | + */ | ||
49 | + | ||
50 | +exports.middleware = {}; | ||
51 | + | ||
52 | +/** | ||
53 | + * Expose utilities. | ||
54 | + */ | ||
55 | + | ||
56 | +exports.utils = utils; | ||
57 | + | ||
58 | +/** | ||
59 | + * Create a new connect server. | ||
60 | + * | ||
61 | + * @return {Function} | ||
62 | + * @api public | ||
63 | + */ | ||
64 | + | ||
65 | +function createServer() { | ||
66 | + function app(req, res){ app.handle(req, res); } | ||
67 | + utils.merge(app, proto); | ||
68 | + utils.merge(app, EventEmitter.prototype); | ||
69 | + app.route = '/'; | ||
70 | + app.stack = []; | ||
71 | + for (var i = 0; i < arguments.length; ++i) { | ||
72 | + app.use(arguments[i]); | ||
73 | + } | ||
74 | + return app; | ||
75 | +}; | ||
76 | + | ||
77 | +/** | ||
78 | + * Support old `.createServer()` method. | ||
79 | + */ | ||
80 | + | ||
81 | +createServer.createServer = createServer; | ||
82 | + | ||
83 | +/** | ||
84 | + * Auto-load bundled middleware with getters. | ||
85 | + */ | ||
86 | + | ||
87 | +fs.readdirSync(__dirname + '/middleware').forEach(function(filename){ | ||
88 | + if (!/\.js$/.test(filename)) return; | ||
89 | + var name = basename(filename, '.js'); | ||
90 | + function load(){ return require('./middleware/' + name); } | ||
91 | + exports.middleware.__defineGetter__(name, load); | ||
92 | + exports.__defineGetter__(name, load); | ||
93 | +}); |
1 | + | ||
2 | +/** | ||
3 | + * Connect is a middleware framework for node, | ||
4 | + * shipping with over 18 bundled middleware and a rich selection of | ||
5 | + * 3rd-party middleware. | ||
6 | + * | ||
7 | + * var app = connect() | ||
8 | + * .use(connect.logger('dev')) | ||
9 | + * .use(connect.static('public')) | ||
10 | + * .use(function(req, res){ | ||
11 | + * res.end('hello world\n'); | ||
12 | + * }) | ||
13 | + * .listen(3000); | ||
14 | + * | ||
15 | + * Installation: | ||
16 | + * | ||
17 | + * $ npm install connect | ||
18 | + * | ||
19 | + * Middleware: | ||
20 | + * | ||
21 | + * - [logger](logger.html) request logger with custom format support | ||
22 | + * - [csrf](csrf.html) Cross-site request forgery protection | ||
23 | + * - [compress](compress.html) Gzip compression middleware | ||
24 | + * - [basicAuth](basicAuth.html) basic http authentication | ||
25 | + * - [bodyParser](bodyParser.html) extensible request body parser | ||
26 | + * - [json](json.html) application/json parser | ||
27 | + * - [urlencoded](urlencoded.html) application/x-www-form-urlencoded parser | ||
28 | + * - [multipart](multipart.html) multipart/form-data parser | ||
29 | + * - [timeout](timeout.html) request timeouts | ||
30 | + * - [cookieParser](cookieParser.html) cookie parser | ||
31 | + * - [session](session.html) session management support with bundled MemoryStore | ||
32 | + * - [cookieSession](cookieSession.html) cookie-based session support | ||
33 | + * - [methodOverride](methodOverride.html) faux HTTP method support | ||
34 | + * - [responseTime](responseTime.html) calculates response-time and exposes via X-Response-Time | ||
35 | + * - [staticCache](staticCache.html) memory cache layer for the static() middleware | ||
36 | + * - [static](static.html) streaming static file server supporting `Range` and more | ||
37 | + * - [directory](directory.html) directory listing middleware | ||
38 | + * - [vhost](vhost.html) virtual host sub-domain mapping middleware | ||
39 | + * - [favicon](favicon.html) efficient favicon server (with default icon) | ||
40 | + * - [limit](limit.html) limit the bytesize of request bodies | ||
41 | + * - [query](query.html) automatic querystring parser, populating `req.query` | ||
42 | + * - [errorHandler](errorHandler.html) flexible error handler | ||
43 | + * | ||
44 | + * Links: | ||
45 | + * | ||
46 | + * - list of [3rd-party](https://github.com/senchalabs/connect/wiki) middleware | ||
47 | + * - GitHub [repository](http://github.com/senchalabs/connect) | ||
48 | + * - [test documentation](https://github.com/senchalabs/connect/blob/gh-pages/tests.md) | ||
49 | + * | ||
50 | + */ | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | + | ||
2 | +/*! | ||
3 | + * Connect - basicAuth | ||
4 | + * Copyright(c) 2010 Sencha Inc. | ||
5 | + * Copyright(c) 2011 TJ Holowaychuk | ||
6 | + * MIT Licensed | ||
7 | + */ | ||
8 | + | ||
9 | +/** | ||
10 | + * Module dependencies. | ||
11 | + */ | ||
12 | + | ||
13 | +var utils = require('../utils') | ||
14 | + , unauthorized = utils.unauthorized; | ||
15 | + | ||
16 | +/** | ||
17 | + * Basic Auth: | ||
18 | + * | ||
19 | + * Enfore basic authentication by providing a `callback(user, pass)`, | ||
20 | + * which must return `true` in order to gain access. Alternatively an async | ||
21 | + * method is provided as well, invoking `callback(user, pass, callback)`. Populates | ||
22 | + * `req.user`. The final alternative is simply passing username / password | ||
23 | + * strings. | ||
24 | + * | ||
25 | + * Simple username and password | ||
26 | + * | ||
27 | + * connect(connect.basicAuth('username', 'password')); | ||
28 | + * | ||
29 | + * Callback verification | ||
30 | + * | ||
31 | + * connect() | ||
32 | + * .use(connect.basicAuth(function(user, pass){ | ||
33 | + * return 'tj' == user & 'wahoo' == pass; | ||
34 | + * })) | ||
35 | + * | ||
36 | + * Async callback verification, accepting `fn(err, user)`. | ||
37 | + * | ||
38 | + * connect() | ||
39 | + * .use(connect.basicAuth(function(user, pass, fn){ | ||
40 | + * User.authenticate({ user: user, pass: pass }, fn); | ||
41 | + * })) | ||
42 | + * | ||
43 | + * @param {Function|String} callback or username | ||
44 | + * @param {String} realm | ||
45 | + * @api public | ||
46 | + */ | ||
47 | + | ||
48 | +module.exports = function basicAuth(callback, realm) { | ||
49 | + var username, password; | ||
50 | + | ||
51 | + // user / pass strings | ||
52 | + if ('string' == typeof callback) { | ||
53 | + username = callback; | ||
54 | + password = realm; | ||
55 | + if ('string' != typeof password) throw new Error('password argument required'); | ||
56 | + realm = arguments[2]; | ||
57 | + callback = function(user, pass){ | ||
58 | + return user == username && pass == password; | ||
59 | + } | ||
60 | + } | ||
61 | + | ||
62 | + realm = realm || 'Authorization Required'; | ||
63 | + | ||
64 | + return function(req, res, next) { | ||
65 | + var authorization = req.headers.authorization; | ||
66 | + | ||
67 | + if (req.user) return next(); | ||
68 | + if (!authorization) return unauthorized(res, realm); | ||
69 | + | ||
70 | + var parts = authorization.split(' ') | ||
71 | + | ||
72 | + if (parts.length !== 2) return next(utils.error(400)); | ||
73 | + | ||
74 | + var scheme = parts[0] | ||
75 | + , credentials = new Buffer(parts[1], 'base64').toString().split(':') | ||
76 | + , user = credentials[0] | ||
77 | + , pass = credentials[1]; | ||
78 | + | ||
79 | + if ('Basic' != scheme) return next(utils.error(400)); | ||
80 | + | ||
81 | + // async | ||
82 | + if (callback.length >= 3) { | ||
83 | + var pause = utils.pause(req); | ||
84 | + callback(user, pass, function(err, user){ | ||
85 | + if (err || !user) return unauthorized(res, realm); | ||
86 | + req.user = req.remoteUser = user; | ||
87 | + next(); | ||
88 | + pause.resume(); | ||
89 | + }); | ||
90 | + // sync | ||
91 | + } else { | ||
92 | + if (callback(user, pass)) { | ||
93 | + req.user = req.remoteUser = user; | ||
94 | + next(); | ||
95 | + } else { | ||
96 | + unauthorized(res, realm); | ||
97 | + } | ||
98 | + } | ||
99 | + } | ||
100 | +}; | ||
101 | + |
1 | + | ||
2 | +/*! | ||
3 | + * Connect - bodyParser | ||
4 | + * Copyright(c) 2010 Sencha Inc. | ||
5 | + * Copyright(c) 2011 TJ Holowaychuk | ||
6 | + * MIT Licensed | ||
7 | + */ | ||
8 | + | ||
9 | +/** | ||
10 | + * Module dependencies. | ||
11 | + */ | ||
12 | + | ||
13 | +var multipart = require('./multipart') | ||
14 | + , urlencoded = require('./urlencoded') | ||
15 | + , json = require('./json'); | ||
16 | + | ||
17 | +/** | ||
18 | + * Body parser: | ||
19 | + * | ||
20 | + * Parse request bodies, supports _application/json_, | ||
21 | + * _application/x-www-form-urlencoded_, and _multipart/form-data_. | ||
22 | + * | ||
23 | + * This is equivalent to: | ||
24 | + * | ||
25 | + * app.use(connect.json()); | ||
26 | + * app.use(connect.urlencoded()); | ||
27 | + * app.use(connect.multipart()); | ||
28 | + * | ||
29 | + * Examples: | ||
30 | + * | ||
31 | + * connect() | ||
32 | + * .use(connect.bodyParser()) | ||
33 | + * .use(function(req, res) { | ||
34 | + * res.end('viewing user ' + req.body.user.name); | ||
35 | + * }); | ||
36 | + * | ||
37 | + * $ curl -d 'user[name]=tj' http://local/ | ||
38 | + * $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://local/ | ||
39 | + * | ||
40 | + * View [json](json.html), [urlencoded](urlencoded.html), and [multipart](multipart.html) for more info. | ||
41 | + * | ||
42 | + * @param {Object} options | ||
43 | + * @return {Function} | ||
44 | + * @api public | ||
45 | + */ | ||
46 | + | ||
47 | +exports = module.exports = function bodyParser(options){ | ||
48 | + var _urlencoded = urlencoded(options) | ||
49 | + , _multipart = multipart(options) | ||
50 | + , _json = json(options); | ||
51 | + | ||
52 | + return function bodyParser(req, res, next) { | ||
53 | + _json(req, res, function(err){ | ||
54 | + if (err) return next(err); | ||
55 | + _urlencoded(req, res, function(err){ | ||
56 | + if (err) return next(err); | ||
57 | + _multipart(req, res, next); | ||
58 | + }); | ||
59 | + }); | ||
60 | + } | ||
61 | +}; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +/*! | ||
2 | + * Connect - compress | ||
3 | + * Copyright(c) 2010 Sencha Inc. | ||
4 | + * Copyright(c) 2011 TJ Holowaychuk | ||
5 | + * MIT Licensed | ||
6 | + */ | ||
7 | + | ||
8 | +/** | ||
9 | + * Module dependencies. | ||
10 | + */ | ||
11 | + | ||
12 | +var zlib = require('zlib'); | ||
13 | + | ||
14 | +/** | ||
15 | + * Supported content-encoding methods. | ||
16 | + */ | ||
17 | + | ||
18 | +exports.methods = { | ||
19 | + gzip: zlib.createGzip | ||
20 | + , deflate: zlib.createDeflate | ||
21 | +}; | ||
22 | + | ||
23 | +/** | ||
24 | + * Default filter function. | ||
25 | + */ | ||
26 | + | ||
27 | +exports.filter = function(req, res){ | ||
28 | + return /json|text|javascript/.test(res.getHeader('Content-Type')); | ||
29 | +}; | ||
30 | + | ||
31 | +/** | ||
32 | + * Compress: | ||
33 | + * | ||
34 | + * Compress response data with gzip/deflate. | ||
35 | + * | ||
36 | + * Filter: | ||
37 | + * | ||
38 | + * A `filter` callback function may be passed to | ||
39 | + * replace the default logic of: | ||
40 | + * | ||
41 | + * exports.filter = function(req, res){ | ||
42 | + * return /json|text|javascript/.test(res.getHeader('Content-Type')); | ||
43 | + * }; | ||
44 | + * | ||
45 | + * Options: | ||
46 | + * | ||
47 | + * All remaining options are passed to the gzip/deflate | ||
48 | + * creation functions. Consult node's docs for additional details. | ||
49 | + * | ||
50 | + * - `chunkSize` (default: 16*1024) | ||
51 | + * - `windowBits` | ||
52 | + * - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression | ||
53 | + * - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more | ||
54 | + * - `strategy`: compression strategy | ||
55 | + * | ||
56 | + * @param {Object} options | ||
57 | + * @return {Function} | ||
58 | + * @api public | ||
59 | + */ | ||
60 | + | ||
61 | +module.exports = function compress(options) { | ||
62 | + var options = options || {} | ||
63 | + , names = Object.keys(exports.methods) | ||
64 | + , filter = options.filter || exports.filter; | ||
65 | + | ||
66 | + return function(req, res, next){ | ||
67 | + var accept = req.headers['accept-encoding'] | ||
68 | + , write = res.write | ||
69 | + , end = res.end | ||
70 | + , stream | ||
71 | + , method; | ||
72 | + | ||
73 | + // vary | ||
74 | + res.setHeader('Vary', 'Accept-Encoding'); | ||
75 | + | ||
76 | + // proxy | ||
77 | + | ||
78 | + res.write = function(chunk, encoding){ | ||
79 | + if (!this.headerSent) this._implicitHeader(); | ||
80 | + return stream | ||
81 | + ? stream.write(new Buffer(chunk, encoding)) | ||
82 | + : write.call(res, chunk, encoding); | ||
83 | + }; | ||
84 | + | ||
85 | + res.end = function(chunk, encoding){ | ||
86 | + if (chunk) this.write(chunk, encoding); | ||
87 | + return stream | ||
88 | + ? stream.end() | ||
89 | + : end.call(res); | ||
90 | + }; | ||
91 | + | ||
92 | + res.on('header', function(){ | ||
93 | + var encoding = res.getHeader('Content-Encoding') || 'identity'; | ||
94 | + | ||
95 | + // already encoded | ||
96 | + if ('identity' != encoding) return; | ||
97 | + | ||
98 | + // default request filter | ||
99 | + if (!filter(req, res)) return; | ||
100 | + | ||
101 | + // SHOULD use identity | ||
102 | + if (!accept) return; | ||
103 | + | ||
104 | + // head | ||
105 | + if ('HEAD' == req.method) return; | ||
106 | + | ||
107 | + // default to gzip | ||
108 | + if ('*' == accept.trim()) method = 'gzip'; | ||
109 | + | ||
110 | + // compression method | ||
111 | + if (!method) { | ||
112 | + for (var i = 0, len = names.length; i < len; ++i) { | ||
113 | + if (~accept.indexOf(names[i])) { | ||
114 | + method = names[i]; | ||
115 | + break; | ||
116 | + } | ||
117 | + } | ||
118 | + } | ||
119 | + | ||
120 | + // compression method | ||
121 | + if (!method) return; | ||
122 | + | ||
123 | + // compression stream | ||
124 | + stream = exports.methods[method](options); | ||
125 | + | ||
126 | + // header fields | ||
127 | + res.setHeader('Content-Encoding', method); | ||
128 | + res.removeHeader('Content-Length'); | ||
129 | + | ||
130 | + // compression | ||
131 | + | ||
132 | + stream.on('data', function(chunk){ | ||
133 | + write.call(res, chunk); | ||
134 | + }); | ||
135 | + | ||
136 | + stream.on('end', function(){ | ||
137 | + end.call(res); | ||
138 | + }); | ||
139 | + | ||
140 | + stream.on('drain', function() { | ||
141 | + res.emit('drain'); | ||
142 | + }); | ||
143 | + }); | ||
144 | + | ||
145 | + next(); | ||
146 | + }; | ||
147 | +} |
1 | + | ||
2 | +/*! | ||
3 | + * Connect - cookieParser | ||
4 | + * Copyright(c) 2010 Sencha Inc. | ||
5 | + * Copyright(c) 2011 TJ Holowaychuk | ||
6 | + * MIT Licensed | ||
7 | + */ | ||
8 | + | ||
9 | +/** | ||
10 | + * Module dependencies. | ||
11 | + */ | ||
12 | + | ||
13 | +var utils = require('./../utils') | ||
14 | + , cookie = require('cookie'); | ||
15 | + | ||
16 | +/** | ||
17 | + * Cookie parser: | ||
18 | + * | ||
19 | + * Parse _Cookie_ header and populate `req.cookies` | ||
20 | + * with an object keyed by the cookie names. Optionally | ||
21 | + * you may enabled signed cookie support by passing | ||
22 | + * a `secret` string, which assigns `req.secret` so | ||
23 | + * it may be used by other middleware. | ||
24 | + * | ||
25 | + * Examples: | ||
26 | + * | ||
27 | + * connect() | ||
28 | + * .use(connect.cookieParser('optional secret string')) | ||
29 | + * .use(function(req, res, next){ | ||
30 | + * res.end(JSON.stringify(req.cookies)); | ||
31 | + * }) | ||
32 | + * | ||
33 | + * @param {String} secret | ||
34 | + * @return {Function} | ||
35 | + * @api public | ||
36 | + */ | ||
37 | + | ||
38 | +module.exports = function cookieParser(secret){ | ||
39 | + return function cookieParser(req, res, next) { | ||
40 | + if (req.cookies) return next(); | ||
41 | + var cookies = req.headers.cookie; | ||
42 | + | ||
43 | + req.secret = secret; | ||
44 | + req.cookies = {}; | ||
45 | + req.signedCookies = {}; | ||
46 | + | ||
47 | + if (cookies) { | ||
48 | + try { | ||
49 | + req.cookies = cookie.parse(cookies); | ||
50 | + if (secret) { | ||
51 | + req.signedCookies = utils.parseSignedCookies(req.cookies, secret); | ||
52 | + var obj = utils.parseJSONCookies(req.signedCookies); | ||
53 | + req.signedCookies = obj; | ||
54 | + } | ||
55 | + req.cookies = utils.parseJSONCookies(req.cookies); | ||
56 | + } catch (err) { | ||
57 | + err.status = 400; | ||
58 | + return next(err); | ||
59 | + } | ||
60 | + } | ||
61 | + next(); | ||
62 | + }; | ||
63 | +}; |
1 | + | ||
2 | +/*! | ||
3 | + * Connect - cookieSession | ||
4 | + * Copyright(c) 2011 Sencha Inc. | ||
5 | + * MIT Licensed | ||
6 | + */ | ||
7 | + | ||
8 | +/** | ||
9 | + * Module dependencies. | ||
10 | + */ | ||
11 | + | ||
12 | +var utils = require('./../utils') | ||
13 | + , Cookie = require('./session/cookie') | ||
14 | + , debug = require('debug')('connect:cookieSession') | ||
15 | + , signature = require('cookie-signature') | ||
16 | + , crc16 = require('crc').crc16; | ||
17 | + | ||
18 | +// environment | ||
19 | + | ||
20 | +var env = process.env.NODE_ENV; | ||
21 | + | ||
22 | +/** | ||
23 | + * Cookie Session: | ||
24 | + * | ||
25 | + * Cookie session middleware. | ||
26 | + * | ||
27 | + * var app = connect(); | ||
28 | + * app.use(connect.cookieParser()); | ||
29 | + * app.use(connect.cookieSession({ secret: 'tobo!', cookie: { maxAge: 60 * 60 * 1000 }})); | ||
30 | + * | ||
31 | + * Options: | ||
32 | + * | ||
33 | + * - `key` cookie name defaulting to `connect.sess` | ||
34 | + * - `secret` prevents cookie tampering | ||
35 | + * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }` | ||
36 | + * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto") | ||
37 | + * | ||
38 | + * Clearing sessions: | ||
39 | + * | ||
40 | + * To clear the session simply set its value to `null`, | ||
41 | + * `cookieSession()` will then respond with a 1970 Set-Cookie. | ||
42 | + * | ||
43 | + * req.session = null; | ||
44 | + * | ||
45 | + * @param {Object} options | ||
46 | + * @return {Function} | ||
47 | + * @api public | ||
48 | + */ | ||
49 | + | ||
50 | +module.exports = function cookieSession(options){ | ||
51 | + // TODO: utilize Session/Cookie to unify API | ||
52 | + var options = options || {} | ||
53 | + , key = options.key || 'connect.sess' | ||
54 | + , trustProxy = options.proxy; | ||
55 | + | ||
56 | + return function cookieSession(req, res, next) { | ||
57 | + | ||
58 | + // req.secret is for backwards compatibility | ||
59 | + var secret = options.secret || req.secret; | ||
60 | + if (!secret) throw new Error('`secret` option required for cookie sessions'); | ||
61 | + | ||
62 | + // default session | ||
63 | + req.session = {}; | ||
64 | + var cookie = req.session.cookie = new Cookie(options.cookie); | ||
65 | + | ||
66 | + // pathname mismatch | ||
67 | + if (0 != req.originalUrl.indexOf(cookie.path)) return next(); | ||
68 | + | ||
69 | + // cookieParser secret | ||
70 | + if (!options.secret && req.secret) { | ||
71 | + req.session = req.signedCookies[key] || {}; | ||
72 | + } else { | ||
73 | + // TODO: refactor | ||
74 | + var rawCookie = req.cookies[key]; | ||
75 | + if (rawCookie) { | ||
76 | + var unsigned = utils.parseSignedCookie(rawCookie, secret); | ||
77 | + if (unsigned) { | ||
78 | + var originalHash = crc16(unsigned); | ||
79 | + req.session = utils.parseJSONCookie(unsigned) || {}; | ||
80 | + } | ||
81 | + } | ||
82 | + } | ||
83 | + | ||
84 | + res.on('header', function(){ | ||
85 | + // removed | ||
86 | + if (!req.session) { | ||
87 | + debug('clear session'); | ||
88 | + cookie.expires = new Date(0); | ||
89 | + res.setHeader('Set-Cookie', cookie.serialize(key, '')); | ||
90 | + return; | ||
91 | + } | ||
92 | + | ||
93 | + delete req.session.cookie; | ||
94 | + | ||
95 | + // check security | ||
96 | + var proto = (req.headers['x-forwarded-proto'] || '').toLowerCase() | ||
97 | + , tls = req.connection.encrypted || (trustProxy && 'https' == proto) | ||
98 | + , secured = cookie.secure && tls; | ||
99 | + | ||
100 | + // only send secure cookies via https | ||
101 | + if (cookie.secure && !secured) return debug('not secured'); | ||
102 | + | ||
103 | + // serialize | ||
104 | + debug('serializing %j', req.session); | ||
105 | + var val = 'j:' + JSON.stringify(req.session); | ||
106 | + | ||
107 | + // compare hashes, no need to set-cookie if unchanged | ||
108 | + if (originalHash == crc16(val)) return debug('unmodified session'); | ||
109 | + | ||
110 | + // set-cookie | ||
111 | + val = 's:' + signature.sign(val, secret); | ||
112 | + val = cookie.serialize(key, val); | ||
113 | + debug('set-cookie %j', cookie); | ||
114 | + res.setHeader('Set-Cookie', val); | ||
115 | + }); | ||
116 | + | ||
117 | + next(); | ||
118 | + }; | ||
119 | +}; |
1 | +/*! | ||
2 | + * Connect - csrf | ||
3 | + * Copyright(c) 2011 Sencha Inc. | ||
4 | + * MIT Licensed | ||
5 | + */ | ||
6 | + | ||
7 | +/** | ||
8 | + * Module dependencies. | ||
9 | + */ | ||
10 | + | ||
11 | +var utils = require('../utils'); | ||
12 | + | ||
13 | +/** | ||
14 | + * Anti CSRF: | ||
15 | + * | ||
16 | + * CRSF protection middleware. | ||
17 | + * | ||
18 | + * By default this middleware generates a token named "_csrf" | ||
19 | + * which should be added to requests which mutate | ||
20 | + * state, within a hidden form field, query-string etc. This | ||
21 | + * token is validated against the visitor's `req.session._csrf` | ||
22 | + * property. | ||
23 | + * | ||
24 | + * The default `value` function checks `req.body` generated | ||
25 | + * by the `bodyParser()` middleware, `req.query` generated | ||
26 | + * by `query()`, and the "X-CSRF-Token" header field. | ||
27 | + * | ||
28 | + * This middleware requires session support, thus should be added | ||
29 | + * somewhere _below_ `session()` and `cookieParser()`. | ||
30 | + * | ||
31 | + * Options: | ||
32 | + * | ||
33 | + * - `value` a function accepting the request, returning the token | ||
34 | + * | ||
35 | + * @param {Object} options | ||
36 | + * @api public | ||
37 | + */ | ||
38 | + | ||
39 | +module.exports = function csrf(options) { | ||
40 | + var options = options || {} | ||
41 | + , value = options.value || defaultValue; | ||
42 | + | ||
43 | + return function(req, res, next){ | ||
44 | + // generate CSRF token | ||
45 | + var token = req.session._csrf || (req.session._csrf = utils.uid(24)); | ||
46 | + | ||
47 | + // ignore these methods | ||
48 | + if ('GET' == req.method || 'HEAD' == req.method || 'OPTIONS' == req.method) return next(); | ||
49 | + | ||
50 | + // determine value | ||
51 | + var val = value(req); | ||
52 | + | ||
53 | + // check | ||
54 | + if (val != token) return next(utils.error(403)); | ||
55 | + | ||
56 | + next(); | ||
57 | + } | ||
58 | +}; | ||
59 | + | ||
60 | +/** | ||
61 | + * Default value function, checking the `req.body` | ||
62 | + * and `req.query` for the CSRF token. | ||
63 | + * | ||
64 | + * @param {IncomingMessage} req | ||
65 | + * @return {String} | ||
66 | + * @api private | ||
67 | + */ | ||
68 | + | ||
69 | +function defaultValue(req) { | ||
70 | + return (req.body && req.body._csrf) | ||
71 | + || (req.query && req.query._csrf) | ||
72 | + || (req.headers['x-csrf-token']); | ||
73 | +} |
1 | + | ||
2 | +/*! | ||
3 | + * Connect - directory | ||
4 | + * Copyright(c) 2011 Sencha Inc. | ||
5 | + * Copyright(c) 2011 TJ Holowaychuk | ||
6 | + * MIT Licensed | ||
7 | + */ | ||
8 | + | ||
9 | +// TODO: icon / style for directories | ||
10 | +// TODO: arrow key navigation | ||
11 | +// TODO: make icons extensible | ||
12 | + | ||
13 | +/** | ||
14 | + * Module dependencies. | ||
15 | + */ | ||
16 | + | ||
17 | +var fs = require('fs') | ||
18 | + , parse = require('url').parse | ||
19 | + , utils = require('../utils') | ||
20 | + , path = require('path') | ||
21 | + , normalize = path.normalize | ||
22 | + , extname = path.extname | ||
23 | + , join = path.join; | ||
24 | + | ||
25 | +/*! | ||
26 | + * Icon cache. | ||
27 | + */ | ||
28 | + | ||
29 | +var cache = {}; | ||
30 | + | ||
31 | +/** | ||
32 | + * Directory: | ||
33 | + * | ||
34 | + * Serve directory listings with the given `root` path. | ||
35 | + * | ||
36 | + * Options: | ||
37 | + * | ||
38 | + * - `hidden` display hidden (dot) files. Defaults to false. | ||
39 | + * - `icons` display icons. Defaults to false. | ||
40 | + * - `filter` Apply this filter function to files. Defaults to false. | ||
41 | + * | ||
42 | + * @param {String} root | ||
43 | + * @param {Object} options | ||
44 | + * @return {Function} | ||
45 | + * @api public | ||
46 | + */ | ||
47 | + | ||
48 | +exports = module.exports = function directory(root, options){ | ||
49 | + options = options || {}; | ||
50 | + | ||
51 | + // root required | ||
52 | + if (!root) throw new Error('directory() root path required'); | ||
53 | + var hidden = options.hidden | ||
54 | + , icons = options.icons | ||
55 | + , filter = options.filter | ||
56 | + , root = normalize(root); | ||
57 | + | ||
58 | + return function directory(req, res, next) { | ||
59 | + if ('GET' != req.method && 'HEAD' != req.method) return next(); | ||
60 | + | ||
61 | + var accept = req.headers.accept || 'text/plain' | ||
62 | + , url = parse(req.url) | ||
63 | + , dir = decodeURIComponent(url.pathname) | ||
64 | + , path = normalize(join(root, dir)) | ||
65 | + , originalUrl = parse(req.originalUrl) | ||
66 | + , originalDir = decodeURIComponent(originalUrl.pathname) | ||
67 | + , showUp = path != root && path != root + '/'; | ||
68 | + | ||
69 | + // null byte(s), bad request | ||
70 | + if (~path.indexOf('\0')) return next(utils.error(400)); | ||
71 | + | ||
72 | + // malicious path, forbidden | ||
73 | + if (0 != path.indexOf(root)) return next(utils.error(403)); | ||
74 | + | ||
75 | + // check if we have a directory | ||
76 | + fs.stat(path, function(err, stat){ | ||
77 | + if (err) return 'ENOENT' == err.code | ||
78 | + ? next() | ||
79 | + : next(err); | ||
80 | + | ||
81 | + if (!stat.isDirectory()) return next(); | ||
82 | + | ||
83 | + // fetch files | ||
84 | + fs.readdir(path, function(err, files){ | ||
85 | + if (err) return next(err); | ||
86 | + if (!hidden) files = removeHidden(files); | ||
87 | + if (filter) files = files.filter(filter); | ||
88 | + files.sort(); | ||
89 | + | ||
90 | + // content-negotiation | ||
91 | + for (var key in exports) { | ||
92 | + if (~accept.indexOf(key) || ~accept.indexOf('*/*')) { | ||
93 | + exports[key](req, res, files, next, originalDir, showUp, icons); | ||
94 | + return; | ||
95 | + } | ||
96 | + } | ||
97 | + | ||
98 | + // not acceptable | ||
99 | + next(utils.error(406)); | ||
100 | + }); | ||
101 | + }); | ||
102 | + }; | ||
103 | +}; | ||
104 | + | ||
105 | +/** | ||
106 | + * Respond with text/html. | ||
107 | + */ | ||
108 | + | ||
109 | +exports.html = function(req, res, files, next, dir, showUp, icons){ | ||
110 | + fs.readFile(__dirname + '/../public/directory.html', 'utf8', function(err, str){ | ||
111 | + if (err) return next(err); | ||
112 | + fs.readFile(__dirname + '/../public/style.css', 'utf8', function(err, style){ | ||
113 | + if (err) return next(err); | ||
114 | + if (showUp) files.unshift('..'); | ||
115 | + str = str | ||
116 | + .replace('{style}', style) | ||
117 | + .replace('{files}', html(files, dir, icons)) | ||
118 | + .replace('{directory}', dir) | ||
119 | + .replace('{linked-path}', htmlPath(dir)); | ||
120 | + res.setHeader('Content-Type', 'text/html'); | ||
121 | + res.setHeader('Content-Length', str.length); | ||
122 | + res.end(str); | ||
123 | + }); | ||
124 | + }); | ||
125 | +}; | ||
126 | + | ||
127 | +/** | ||
128 | + * Respond with application/json. | ||
129 | + */ | ||
130 | + | ||
131 | +exports.json = function(req, res, files){ | ||
132 | + files = JSON.stringify(files); | ||
133 | + res.setHeader('Content-Type', 'application/json'); | ||
134 | + res.setHeader('Content-Length', files.length); | ||
135 | + res.end(files); | ||
136 | +}; | ||
137 | + | ||
138 | +/** | ||
139 | + * Respond with text/plain. | ||
140 | + */ | ||
141 | + | ||
142 | +exports.plain = function(req, res, files){ | ||
143 | + files = files.join('\n') + '\n'; | ||
144 | + res.setHeader('Content-Type', 'text/plain'); | ||
145 | + res.setHeader('Content-Length', files.length); | ||
146 | + res.end(files); | ||
147 | +}; | ||
148 | + | ||
149 | +/** | ||
150 | + * Map html `dir`, returning a linked path. | ||
151 | + */ | ||
152 | + | ||
153 | +function htmlPath(dir) { | ||
154 | + var curr = []; | ||
155 | + return dir.split('/').map(function(part){ | ||
156 | + curr.push(part); | ||
157 | + return '<a href="' + curr.join('/') + '">' + part + '</a>'; | ||
158 | + }).join(' / '); | ||
159 | +} | ||
160 | + | ||
161 | +/** | ||
162 | + * Map html `files`, returning an html unordered list. | ||
163 | + */ | ||
164 | + | ||
165 | +function html(files, dir, useIcons) { | ||
166 | + return '<ul id="files">' + files.map(function(file){ | ||
167 | + var icon = '' | ||
168 | + , classes = []; | ||
169 | + | ||
170 | + if (useIcons && '..' != file) { | ||
171 | + icon = icons[extname(file)] || icons.default; | ||
172 | + icon = '<img src="data:image/png;base64,' + load(icon) + '" />'; | ||
173 | + classes.push('icon'); | ||
174 | + } | ||
175 | + | ||
176 | + return '<li><a href="' | ||
177 | + + join(dir, file) | ||
178 | + + '" class="' | ||
179 | + + classes.join(' ') + '"' | ||
180 | + + ' title="' + file + '">' | ||
181 | + + icon + file + '</a></li>'; | ||
182 | + | ||
183 | + }).join('\n') + '</ul>'; | ||
184 | +} | ||
185 | + | ||
186 | +/** | ||
187 | + * Load and cache the given `icon`. | ||
188 | + * | ||
189 | + * @param {String} icon | ||
190 | + * @return {String} | ||
191 | + * @api private | ||
192 | + */ | ||
193 | + | ||
194 | +function load(icon) { | ||
195 | + if (cache[icon]) return cache[icon]; | ||
196 | + return cache[icon] = fs.readFileSync(__dirname + '/../public/icons/' + icon, 'base64'); | ||
197 | +} | ||
198 | + | ||
199 | +/** | ||
200 | + * Filter "hidden" `files`, aka files | ||
201 | + * beginning with a `.`. | ||
202 | + * | ||
203 | + * @param {Array} files | ||
204 | + * @return {Array} | ||
205 | + * @api private | ||
206 | + */ | ||
207 | + | ||
208 | +function removeHidden(files) { | ||
209 | + return files.filter(function(file){ | ||
210 | + return '.' != file[0]; | ||
211 | + }); | ||
212 | +} | ||
213 | + | ||
214 | +/** | ||
215 | + * Icon map. | ||
216 | + */ | ||
217 | + | ||
218 | +var icons = { | ||
219 | + '.js': 'page_white_code_red.png' | ||
220 | + , '.c': 'page_white_c.png' | ||
221 | + , '.h': 'page_white_h.png' | ||
222 | + , '.cc': 'page_white_cplusplus.png' | ||
223 | + , '.php': 'page_white_php.png' | ||
224 | + , '.rb': 'page_white_ruby.png' | ||
225 | + , '.cpp': 'page_white_cplusplus.png' | ||
226 | + , '.swf': 'page_white_flash.png' | ||
227 | + , '.pdf': 'page_white_acrobat.png' | ||
228 | + , 'default': 'page_white.png' | ||
229 | +}; |
1 | +/*! | ||
2 | + * Connect - errorHandler | ||
3 | + * Copyright(c) 2010 Sencha Inc. | ||
4 | + * Copyright(c) 2011 TJ Holowaychuk | ||
5 | + * MIT Licensed | ||
6 | + */ | ||
7 | + | ||
8 | +/** | ||
9 | + * Module dependencies. | ||
10 | + */ | ||
11 | + | ||
12 | +var utils = require('../utils') | ||
13 | + , fs = require('fs'); | ||
14 | + | ||
15 | +// environment | ||
16 | + | ||
17 | +var env = process.env.NODE_ENV || 'development'; | ||
18 | + | ||
19 | +/** | ||
20 | + * Error handler: | ||
21 | + * | ||
22 | + * Development error handler, providing stack traces | ||
23 | + * and error message responses for requests accepting text, html, | ||
24 | + * or json. | ||
25 | + * | ||
26 | + * Text: | ||
27 | + * | ||
28 | + * By default, and when _text/plain_ is accepted a simple stack trace | ||
29 | + * or error message will be returned. | ||
30 | + * | ||
31 | + * JSON: | ||
32 | + * | ||
33 | + * When _application/json_ is accepted, connect will respond with | ||
34 | + * an object in the form of `{ "error": error }`. | ||
35 | + * | ||
36 | + * HTML: | ||
37 | + * | ||
38 | + * When accepted connect will output a nice html stack trace. | ||
39 | + * | ||
40 | + * @return {Function} | ||
41 | + * @api public | ||
42 | + */ | ||
43 | + | ||
44 | +exports = module.exports = function errorHandler(){ | ||
45 | + return function errorHandler(err, req, res, next){ | ||
46 | + if (err.status) res.statusCode = err.status; | ||
47 | + if (res.statusCode < 400) res.statusCode = 500; | ||
48 | + if ('test' != env) console.error(err.stack); | ||
49 | + var accept = req.headers.accept || ''; | ||
50 | + // html | ||
51 | + if (~accept.indexOf('html')) { | ||
52 | + fs.readFile(__dirname + '/../public/style.css', 'utf8', function(e, style){ | ||
53 | + fs.readFile(__dirname + '/../public/error.html', 'utf8', function(e, html){ | ||
54 | + var stack = (err.stack || '') | ||
55 | + .split('\n').slice(1) | ||
56 | + .map(function(v){ return '<li>' + v + '</li>'; }).join(''); | ||
57 | + html = html | ||
58 | + .replace('{style}', style) | ||
59 | + .replace('{stack}', stack) | ||
60 | + .replace('{title}', exports.title) | ||
61 | + .replace('{statusCode}', res.statusCode) | ||
62 | + .replace(/\{error\}/g, utils.escape(err.toString())); | ||
63 | + res.setHeader('Content-Type', 'text/html; charset=utf-8'); | ||
64 | + res.end(html); | ||
65 | + }); | ||
66 | + }); | ||
67 | + // json | ||
68 | + } else if (~accept.indexOf('json')) { | ||
69 | + var error = { message: err.message, stack: err.stack }; | ||
70 | + for (var prop in err) error[prop] = err[prop]; | ||
71 | + var json = JSON.stringify({ error: error }); | ||
72 | + res.setHeader('Content-Type', 'application/json'); | ||
73 | + res.end(json); | ||
74 | + // plain text | ||
75 | + } else { | ||
76 | + res.writeHead(res.statusCode, { 'Content-Type': 'text/plain' }); | ||
77 | + res.end(err.stack); | ||
78 | + } | ||
79 | + }; | ||
80 | +}; | ||
81 | + | ||
82 | +/** | ||
83 | + * Template title, framework authors may override this value. | ||
84 | + */ | ||
85 | + | ||
86 | +exports.title = 'Connect'; |
1 | + | ||
2 | +/*! | ||
3 | + * Connect - favicon | ||
4 | + * Copyright(c) 2010 Sencha Inc. | ||
5 | + * Copyright(c) 2011 TJ Holowaychuk | ||
6 | + * MIT Licensed | ||
7 | + */ | ||
8 | + | ||
9 | +/** | ||
10 | + * Module dependencies. | ||
11 | + */ | ||
12 | + | ||
13 | +var fs = require('fs') | ||
14 | + , utils = require('../utils'); | ||
15 | + | ||
16 | +/** | ||
17 | + * Favicon: | ||
18 | + * | ||
19 | + * By default serves the connect favicon, or the favicon | ||
20 | + * located by the given `path`. | ||
21 | + * | ||
22 | + * Options: | ||
23 | + * | ||
24 | + * - `maxAge` cache-control max-age directive, defaulting to 1 day | ||
25 | + * | ||
26 | + * Examples: | ||
27 | + * | ||
28 | + * Serve default favicon: | ||
29 | + * | ||
30 | + * connect() | ||
31 | + * .use(connect.favicon()) | ||
32 | + * | ||
33 | + * Serve favicon before logging for brevity: | ||
34 | + * | ||
35 | + * connect() | ||
36 | + * .use(connect.favicon()) | ||
37 | + * .use(connect.logger('dev')) | ||
38 | + * | ||
39 | + * Serve custom favicon: | ||
40 | + * | ||
41 | + * connect() | ||
42 | + * .use(connect.favicon('public/favicon.ico)) | ||
43 | + * | ||
44 | + * @param {String} path | ||
45 | + * @param {Object} options | ||
46 | + * @return {Function} | ||
47 | + * @api public | ||
48 | + */ | ||
49 | + | ||
50 | +module.exports = function favicon(path, options){ | ||
51 | + var options = options || {} | ||
52 | + , path = path || __dirname + '/../public/favicon.ico' | ||
53 | + , maxAge = options.maxAge || 86400000 | ||
54 | + , icon; // favicon cache | ||
55 | + | ||
56 | + return function favicon(req, res, next){ | ||
57 | + if ('/favicon.ico' == req.url) { | ||
58 | + if (icon) { | ||
59 | + res.writeHead(200, icon.headers); | ||
60 | + res.end(icon.body); | ||
61 | + } else { | ||
62 | + fs.readFile(path, function(err, buf){ | ||
63 | + if (err) return next(err); | ||
64 | + icon = { | ||
65 | + headers: { | ||
66 | + 'Content-Type': 'image/x-icon' | ||
67 | + , 'Content-Length': buf.length | ||
68 | + , 'ETag': '"' + utils.md5(buf) + '"' | ||
69 | + , 'Cache-Control': 'public, max-age=' + (maxAge / 1000) | ||
70 | + }, | ||
71 | + body: buf | ||
72 | + }; | ||
73 | + res.writeHead(200, icon.headers); | ||
74 | + res.end(icon.body); | ||
75 | + }); | ||
76 | + } | ||
77 | + } else { | ||
78 | + next(); | ||
79 | + } | ||
80 | + }; | ||
81 | +}; |
1 | + | ||
2 | +/*! | ||
3 | + * Connect - json | ||
4 | + * Copyright(c) 2010 Sencha Inc. | ||
5 | + * Copyright(c) 2011 TJ Holowaychuk | ||
6 | + * MIT Licensed | ||
7 | + */ | ||
8 | + | ||
9 | +/** | ||
10 | + * Module dependencies. | ||
11 | + */ | ||
12 | + | ||
13 | +var utils = require('../utils') | ||
14 | + , _limit = require('./limit'); | ||
15 | + | ||
16 | +/** | ||
17 | + * noop middleware. | ||
18 | + */ | ||
19 | + | ||
20 | +function noop(req, res, next) { | ||
21 | + next(); | ||
22 | +} | ||
23 | + | ||
24 | +/** | ||
25 | + * JSON: | ||
26 | + * | ||
27 | + * Parse JSON request bodies, providing the | ||
28 | + * parsed object as `req.body`. | ||
29 | + * | ||
30 | + * Options: | ||
31 | + * | ||
32 | + * - `strict` when `false` anything `JSON.parse()` accepts will be parsed | ||
33 | + * - `reviver` used as the second "reviver" argument for JSON.parse | ||
34 | + * - `limit` byte limit disabled by default | ||
35 | + * | ||
36 | + * @param {Object} options | ||
37 | + * @return {Function} | ||
38 | + * @api public | ||
39 | + */ | ||
40 | + | ||
41 | +exports = module.exports = function(options){ | ||
42 | + var options = options || {} | ||
43 | + , strict = options.strict === false | ||
44 | + ? false | ||
45 | + : true; | ||
46 | + | ||
47 | + var limit = options.limit | ||
48 | + ? _limit(options.limit) | ||
49 | + : noop; | ||
50 | + | ||
51 | + return function json(req, res, next) { | ||
52 | + if (req._body) return next(); | ||
53 | + req.body = req.body || {}; | ||
54 | + | ||
55 | + // check Content-Type | ||
56 | + if ('application/json' != utils.mime(req)) return next(); | ||
57 | + | ||
58 | + // flag as parsed | ||
59 | + req._body = true; | ||
60 | + | ||
61 | + // parse | ||
62 | + limit(req, res, function(err){ | ||
63 | + if (err) return next(err); | ||
64 | + var buf = ''; | ||
65 | + req.setEncoding('utf8'); | ||
66 | + req.on('data', function(chunk){ buf += chunk }); | ||
67 | + req.on('end', function(){ | ||
68 | + if (strict && '{' != buf[0] && '[' != buf[0]) return next(utils.error(400, 'invalid json')); | ||
69 | + try { | ||
70 | + req.body = JSON.parse(buf, options.reviver); | ||
71 | + next(); | ||
72 | + } catch (err){ | ||
73 | + err.body = buf; | ||
74 | + err.status = 400; | ||
75 | + next(err); | ||
76 | + } | ||
77 | + }); | ||
78 | + }); | ||
79 | + } | ||
80 | +}; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | + | ||
2 | +/*! | ||
3 | + * Connect - limit | ||
4 | + * Copyright(c) 2011 TJ Holowaychuk | ||
5 | + * MIT Licensed | ||
6 | + */ | ||
7 | + | ||
8 | +/** | ||
9 | + * Module dependencies. | ||
10 | + */ | ||
11 | + | ||
12 | +var utils = require('../utils'); | ||
13 | + | ||
14 | +/** | ||
15 | + * Limit: | ||
16 | + * | ||
17 | + * Limit request bodies to the given size in `bytes`. | ||
18 | + * | ||
19 | + * A string representation of the bytesize may also be passed, | ||
20 | + * for example "5mb", "200kb", "1gb", etc. | ||
21 | + * | ||
22 | + * connect() | ||
23 | + * .use(connect.limit('5.5mb')) | ||
24 | + * .use(handleImageUpload) | ||
25 | + * | ||
26 | + * @param {Number|String} bytes | ||
27 | + * @return {Function} | ||
28 | + * @api public | ||
29 | + */ | ||
30 | + | ||
31 | +module.exports = function limit(bytes){ | ||
32 | + if ('string' == typeof bytes) bytes = utils.parseBytes(bytes); | ||
33 | + if ('number' != typeof bytes) throw new Error('limit() bytes required'); | ||
34 | + return function limit(req, res, next){ | ||
35 | + var received = 0 | ||
36 | + , len = req.headers['content-length'] | ||
37 | + ? parseInt(req.headers['content-length'], 10) | ||
38 | + : null; | ||
39 | + | ||
40 | + // self-awareness | ||
41 | + if (req._limit) return next(); | ||
42 | + req._limit = true; | ||
43 | + | ||
44 | + // limit by content-length | ||
45 | + if (len && len > bytes) return next(utils.error(413)); | ||
46 | + | ||
47 | + // limit | ||
48 | + req.on('data', function(chunk){ | ||
49 | + received += chunk.length; | ||
50 | + if (received > bytes) req.destroy(); | ||
51 | + }); | ||
52 | + | ||
53 | + next(); | ||
54 | + }; | ||
55 | +}; |
1 | +/*! | ||
2 | + * Connect - logger | ||
3 | + * Copyright(c) 2010 Sencha Inc. | ||
4 | + * Copyright(c) 2011 TJ Holowaychuk | ||
5 | + * MIT Licensed | ||
6 | + */ | ||
7 | + | ||
8 | +/** | ||
9 | + * Module dependencies. | ||
10 | + */ | ||
11 | + | ||
12 | +var bytes = require('bytes'); | ||
13 | + | ||
14 | +/*! | ||
15 | + * Log buffer. | ||
16 | + */ | ||
17 | + | ||
18 | +var buf = []; | ||
19 | + | ||
20 | +/*! | ||
21 | + * Default log buffer duration. | ||
22 | + */ | ||
23 | + | ||
24 | +var defaultBufferDuration = 1000; | ||
25 | + | ||
26 | +/** | ||
27 | + * Logger: | ||
28 | + * | ||
29 | + * Log requests with the given `options` or a `format` string. | ||
30 | + * | ||
31 | + * Options: | ||
32 | + * | ||
33 | + * - `format` Format string, see below for tokens | ||
34 | + * - `stream` Output stream, defaults to _stdout_ | ||
35 | + * - `buffer` Buffer duration, defaults to 1000ms when _true_ | ||
36 | + * - `immediate` Write log line on request instead of response (for response times) | ||
37 | + * | ||
38 | + * Tokens: | ||
39 | + * | ||
40 | + * - `:req[header]` ex: `:req[Accept]` | ||
41 | + * - `:res[header]` ex: `:res[Content-Length]` | ||
42 | + * - `:http-version` | ||
43 | + * - `:response-time` | ||
44 | + * - `:remote-addr` | ||
45 | + * - `:date` | ||
46 | + * - `:method` | ||
47 | + * - `:url` | ||
48 | + * - `:referrer` | ||
49 | + * - `:user-agent` | ||
50 | + * - `:status` | ||
51 | + * | ||
52 | + * Formats: | ||
53 | + * | ||
54 | + * Pre-defined formats that ship with connect: | ||
55 | + * | ||
56 | + * - `default` ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"' | ||
57 | + * - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms' | ||
58 | + * - `tiny` ':method :url :status :res[content-length] - :response-time ms' | ||
59 | + * - `dev` concise output colored by response status for development use | ||
60 | + * | ||
61 | + * Examples: | ||
62 | + * | ||
63 | + * connect.logger() // default | ||
64 | + * connect.logger('short') | ||
65 | + * connect.logger('tiny') | ||
66 | + * connect.logger({ immediate: true, format: 'dev' }) | ||
67 | + * connect.logger(':method :url - :referrer') | ||
68 | + * connect.logger(':req[content-type] -> :res[content-type]') | ||
69 | + * connect.logger(function(req, res){ return 'some format string' }) | ||
70 | + * | ||
71 | + * Defining Tokens: | ||
72 | + * | ||
73 | + * To define a token, simply invoke `connect.logger.token()` with the | ||
74 | + * name and a callback function. The value returned is then available | ||
75 | + * as ":type" in this case. | ||
76 | + * | ||
77 | + * connect.logger.token('type', function(req, res){ return req.headers['content-type']; }) | ||
78 | + * | ||
79 | + * Defining Formats: | ||
80 | + * | ||
81 | + * All default formats are defined this way, however it's public API as well: | ||
82 | + * | ||
83 | + * connect.logger.format('name', 'string or function') | ||
84 | + * | ||
85 | + * @param {String|Function|Object} format or options | ||
86 | + * @return {Function} | ||
87 | + * @api public | ||
88 | + */ | ||
89 | + | ||
90 | +exports = module.exports = function logger(options) { | ||
91 | + if ('object' == typeof options) { | ||
92 | + options = options || {}; | ||
93 | + } else if (options) { | ||
94 | + options = { format: options }; | ||
95 | + } else { | ||
96 | + options = {}; | ||
97 | + } | ||
98 | + | ||
99 | + // output on request instead of response | ||
100 | + var immediate = options.immediate; | ||
101 | + | ||
102 | + // format name | ||
103 | + var fmt = exports[options.format] || options.format || exports.default; | ||
104 | + | ||
105 | + // compile format | ||
106 | + if ('function' != typeof fmt) fmt = compile(fmt); | ||
107 | + | ||
108 | + // options | ||
109 | + var stream = options.stream || process.stdout | ||
110 | + , buffer = options.buffer; | ||
111 | + | ||
112 | + // buffering support | ||
113 | + if (buffer) { | ||
114 | + var realStream = stream | ||
115 | + , interval = 'number' == typeof buffer | ||
116 | + ? buffer | ||
117 | + : defaultBufferDuration; | ||
118 | + | ||
119 | + // flush interval | ||
120 | + setInterval(function(){ | ||
121 | + if (buf.length) { | ||
122 | + realStream.write(buf.join('')); | ||
123 | + buf.length = 0; | ||
124 | + } | ||
125 | + }, interval); | ||
126 | + | ||
127 | + // swap the stream | ||
128 | + stream = { | ||
129 | + write: function(str){ | ||
130 | + buf.push(str); | ||
131 | + } | ||
132 | + }; | ||
133 | + } | ||
134 | + | ||
135 | + return function logger(req, res, next) { | ||
136 | + req._startTime = new Date; | ||
137 | + | ||
138 | + // immediate | ||
139 | + if (immediate) { | ||
140 | + var line = fmt(exports, req, res); | ||
141 | + if (null == line) return; | ||
142 | + stream.write(line + '\n'); | ||
143 | + // proxy end to output logging | ||
144 | + } else { | ||
145 | + var end = res.end; | ||
146 | + res.end = function(chunk, encoding){ | ||
147 | + res.end = end; | ||
148 | + res.end(chunk, encoding); | ||
149 | + var line = fmt(exports, req, res); | ||
150 | + if (null == line) return; | ||
151 | + stream.write(line + '\n'); | ||
152 | + }; | ||
153 | + } | ||
154 | + | ||
155 | + | ||
156 | + next(); | ||
157 | + }; | ||
158 | +}; | ||
159 | + | ||
160 | +/** | ||
161 | + * Compile `fmt` into a function. | ||
162 | + * | ||
163 | + * @param {String} fmt | ||
164 | + * @return {Function} | ||
165 | + * @api private | ||
166 | + */ | ||
167 | + | ||
168 | +function compile(fmt) { | ||
169 | + fmt = fmt.replace(/"/g, '\\"'); | ||
170 | + var js = ' return "' + fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, function(_, name, arg){ | ||
171 | + return '"\n + (tokens["' + name + '"](req, res, "' + arg + '") || "-") + "'; | ||
172 | + }) + '";' | ||
173 | + return new Function('tokens, req, res', js); | ||
174 | +}; | ||
175 | + | ||
176 | +/** | ||
177 | + * Define a token function with the given `name`, | ||
178 | + * and callback `fn(req, res)`. | ||
179 | + * | ||
180 | + * @param {String} name | ||
181 | + * @param {Function} fn | ||
182 | + * @return {Object} exports for chaining | ||
183 | + * @api public | ||
184 | + */ | ||
185 | + | ||
186 | +exports.token = function(name, fn) { | ||
187 | + exports[name] = fn; | ||
188 | + return this; | ||
189 | +}; | ||
190 | + | ||
191 | +/** | ||
192 | + * Define a `fmt` with the given `name`. | ||
193 | + * | ||
194 | + * @param {String} name | ||
195 | + * @param {String|Function} fmt | ||
196 | + * @return {Object} exports for chaining | ||
197 | + * @api public | ||
198 | + */ | ||
199 | + | ||
200 | +exports.format = function(name, str){ | ||
201 | + exports[name] = str; | ||
202 | + return this; | ||
203 | +}; | ||
204 | + | ||
205 | +/** | ||
206 | + * Default format. | ||
207 | + */ | ||
208 | + | ||
209 | +exports.format('default', ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'); | ||
210 | + | ||
211 | +/** | ||
212 | + * Short format. | ||
213 | + */ | ||
214 | + | ||
215 | +exports.format('short', ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'); | ||
216 | + | ||
217 | +/** | ||
218 | + * Tiny format. | ||
219 | + */ | ||
220 | + | ||
221 | +exports.format('tiny', ':method :url :status :res[content-length] - :response-time ms'); | ||
222 | + | ||
223 | +/** | ||
224 | + * dev (colored) | ||
225 | + */ | ||
226 | + | ||
227 | +exports.format('dev', function(tokens, req, res){ | ||
228 | + var status = res.statusCode | ||
229 | + , len = parseInt(res.getHeader('Content-Length'), 10) | ||
230 | + , color = 32; | ||
231 | + | ||
232 | + if (status >= 500) color = 31 | ||
233 | + else if (status >= 400) color = 33 | ||
234 | + else if (status >= 300) color = 36; | ||
235 | + | ||
236 | + len = isNaN(len) | ||
237 | + ? '' | ||
238 | + : len = ' - ' + bytes(len); | ||
239 | + | ||
240 | + return '\033[90m' + req.method | ||
241 | + + ' ' + req.originalUrl + ' ' | ||
242 | + + '\033[' + color + 'm' + res.statusCode | ||
243 | + + ' \033[90m' | ||
244 | + + (new Date - req._startTime) | ||
245 | + + 'ms' + len | ||
246 | + + '\033[0m'; | ||
247 | +}); | ||
248 | + | ||
249 | +/** | ||
250 | + * request url | ||
251 | + */ | ||
252 | + | ||
253 | +exports.token('url', function(req){ | ||
254 | + return req.originalUrl || req.url; | ||
255 | +}); | ||
256 | + | ||
257 | +/** | ||
258 | + * request method | ||
259 | + */ | ||
260 | + | ||
261 | +exports.token('method', function(req){ | ||
262 | + return req.method; | ||
263 | +}); | ||
264 | + | ||
265 | +/** | ||
266 | + * response time in milliseconds | ||
267 | + */ | ||
268 | + | ||
269 | +exports.token('response-time', function(req){ | ||
270 | + return new Date - req._startTime; | ||
271 | +}); | ||
272 | + | ||
273 | +/** | ||
274 | + * UTC date | ||
275 | + */ | ||
276 | + | ||
277 | +exports.token('date', function(){ | ||
278 | + return new Date().toUTCString(); | ||
279 | +}); | ||
280 | + | ||
281 | +/** | ||
282 | + * response status code | ||
283 | + */ | ||
284 | + | ||
285 | +exports.token('status', function(req, res){ | ||
286 | + return res.statusCode; | ||
287 | +}); | ||
288 | + | ||
289 | +/** | ||
290 | + * normalized referrer | ||
291 | + */ | ||
292 | + | ||
293 | +exports.token('referrer', function(req){ | ||
294 | + return req.headers['referer'] || req.headers['referrer']; | ||
295 | +}); | ||
296 | + | ||
297 | +/** | ||
298 | + * remote address | ||
299 | + */ | ||
300 | + | ||
301 | +exports.token('remote-addr', function(req){ | ||
302 | + return req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress)); | ||
303 | +}); | ||
304 | + | ||
305 | +/** | ||
306 | + * HTTP version | ||
307 | + */ | ||
308 | + | ||
309 | +exports.token('http-version', function(req){ | ||
310 | + return req.httpVersionMajor + '.' + req.httpVersionMinor; | ||
311 | +}); | ||
312 | + | ||
313 | +/** | ||
314 | + * UA string | ||
315 | + */ | ||
316 | + | ||
317 | +exports.token('user-agent', function(req){ | ||
318 | + return req.headers['user-agent']; | ||
319 | +}); | ||
320 | + | ||
321 | +/** | ||
322 | + * request header | ||
323 | + */ | ||
324 | + | ||
325 | +exports.token('req', function(req, res, field){ | ||
326 | + return req.headers[field.toLowerCase()]; | ||
327 | +}); | ||
328 | + | ||
329 | +/** | ||
330 | + * response header | ||
331 | + */ | ||
332 | + | ||
333 | +exports.token('res', function(req, res, field){ | ||
334 | + return (res._headers || {})[field.toLowerCase()]; | ||
335 | +}); | ||
336 | + |
1 | + | ||
2 | +/*! | ||
3 | + * Connect - methodOverride | ||
4 | + * Copyright(c) 2010 Sencha Inc. | ||
5 | + * Copyright(c) 2011 TJ Holowaychuk | ||
6 | + * MIT Licensed | ||
7 | + */ | ||
8 | + | ||
9 | +/** | ||
10 | + * Method Override: | ||
11 | + * | ||
12 | + * Provides faux HTTP method support. | ||
13 | + * | ||
14 | + * Pass an optional `key` to use when checking for | ||
15 | + * a method override, othewise defaults to _\_method_. | ||
16 | + * The original method is available via `req.originalMethod`. | ||
17 | + * | ||
18 | + * @param {String} key | ||
19 | + * @return {Function} | ||
20 | + * @api public | ||
21 | + */ | ||
22 | + | ||
23 | +module.exports = function methodOverride(key){ | ||
24 | + key = key || "_method"; | ||
25 | + return function methodOverride(req, res, next) { | ||
26 | + req.originalMethod = req.originalMethod || req.method; | ||
27 | + | ||
28 | + // req.body | ||
29 | + if (req.body && key in req.body) { | ||
30 | + req.method = req.body[key].toUpperCase(); | ||
31 | + delete req.body[key]; | ||
32 | + // check X-HTTP-Method-Override | ||
33 | + } else if (req.headers['x-http-method-override']) { | ||
34 | + req.method = req.headers['x-http-method-override'].toUpperCase(); | ||
35 | + } | ||
36 | + | ||
37 | + next(); | ||
38 | + }; | ||
39 | +}; | ||
40 | + |
1 | +/*! | ||
2 | + * Connect - multipart | ||
3 | + * Copyright(c) 2010 Sencha Inc. | ||
4 | + * Copyright(c) 2011 TJ Holowaychuk | ||
5 | + * MIT Licensed | ||
6 | + */ | ||
7 | + | ||
8 | +/** | ||
9 | + * Module dependencies. | ||
10 | + */ | ||
11 | + | ||
12 | +var formidable = require('formidable') | ||
13 | + , _limit = require('./limit') | ||
14 | + , utils = require('../utils') | ||
15 | + , qs = require('qs'); | ||
16 | + | ||
17 | +/** | ||
18 | + * noop middleware. | ||
19 | + */ | ||
20 | + | ||
21 | +function noop(req, res, next) { | ||
22 | + next(); | ||
23 | +} | ||
24 | + | ||
25 | +/** | ||
26 | + * Multipart: | ||
27 | + * | ||
28 | + * Parse multipart/form-data request bodies, | ||
29 | + * providing the parsed object as `req.body` | ||
30 | + * and `req.files`. | ||
31 | + * | ||
32 | + * Configuration: | ||
33 | + * | ||
34 | + * The options passed are merged with [formidable](https://github.com/felixge/node-formidable)'s | ||
35 | + * `IncomingForm` object, allowing you to configure the upload directory, | ||
36 | + * size limits, etc. For example if you wish to change the upload dir do the following. | ||
37 | + * | ||
38 | + * app.use(connect.multipart({ uploadDir: path })); | ||
39 | + * | ||
40 | + * Options: | ||
41 | + * | ||
42 | + * - `limit` byte limit defaulting to none | ||
43 | + * - `defer` defers processing and exposes the Formidable form object as `req.form`. | ||
44 | + * `next()` is called without waiting for the form's "end" event. | ||
45 | + * This option is useful if you need to bind to the "progress" event, for example. | ||
46 | + * | ||
47 | + * @param {Object} options | ||
48 | + * @return {Function} | ||
49 | + * @api public | ||
50 | + */ | ||
51 | + | ||
52 | +exports = module.exports = function(options){ | ||
53 | + options = options || {}; | ||
54 | + | ||
55 | + var limit = options.limit | ||
56 | + ? _limit(options.limit) | ||
57 | + : noop; | ||
58 | + | ||
59 | + return function multipart(req, res, next) { | ||
60 | + if (req._body) return next(); | ||
61 | + req.body = req.body || {}; | ||
62 | + req.files = req.files || {}; | ||
63 | + | ||
64 | + // ignore GET | ||
65 | + if ('GET' == req.method || 'HEAD' == req.method) return next(); | ||
66 | + | ||
67 | + // check Content-Type | ||
68 | + if ('multipart/form-data' != utils.mime(req)) return next(); | ||
69 | + | ||
70 | + // flag as parsed | ||
71 | + req._body = true; | ||
72 | + | ||
73 | + // parse | ||
74 | + limit(req, res, function(err){ | ||
75 | + if (err) return next(err); | ||
76 | + | ||
77 | + var form = new formidable.IncomingForm | ||
78 | + , data = {} | ||
79 | + , files = {} | ||
80 | + , done; | ||
81 | + | ||
82 | + Object.keys(options).forEach(function(key){ | ||
83 | + form[key] = options[key]; | ||
84 | + }); | ||
85 | + | ||
86 | + function ondata(name, val, data){ | ||
87 | + if (Array.isArray(data[name])) { | ||
88 | + data[name].push(val); | ||
89 | + } else if (data[name]) { | ||
90 | + data[name] = [data[name], val]; | ||
91 | + } else { | ||
92 | + data[name] = val; | ||
93 | + } | ||
94 | + } | ||
95 | + | ||
96 | + form.on('field', function(name, val){ | ||
97 | + ondata(name, val, data); | ||
98 | + }); | ||
99 | + | ||
100 | + form.on('file', function(name, val){ | ||
101 | + ondata(name, val, files); | ||
102 | + }); | ||
103 | + | ||
104 | + form.on('error', function(err){ | ||
105 | + if (!options.defer) { | ||
106 | + err.status = 400; | ||
107 | + next(err); | ||
108 | + } | ||
109 | + done = true; | ||
110 | + }); | ||
111 | + | ||
112 | + form.on('end', function(){ | ||
113 | + if (done) return; | ||
114 | + try { | ||
115 | + req.body = qs.parse(data); | ||
116 | + req.files = qs.parse(files); | ||
117 | + if (!options.defer) next(); | ||
118 | + } catch (err) { | ||
119 | + form.emit('error', err); | ||
120 | + } | ||
121 | + }); | ||
122 | + | ||
123 | + form.parse(req); | ||
124 | + | ||
125 | + if (options.defer) { | ||
126 | + req.form = form; | ||
127 | + next(); | ||
128 | + } | ||
129 | + }); | ||
130 | + } | ||
131 | +}; |
1 | +/*! | ||
2 | + * Connect - query | ||
3 | + * Copyright(c) 2011 TJ Holowaychuk | ||
4 | + * Copyright(c) 2011 Sencha Inc. | ||
5 | + * MIT Licensed | ||
6 | + */ | ||
7 | + | ||
8 | +/** | ||
9 | + * Module dependencies. | ||
10 | + */ | ||
11 | + | ||
12 | +var qs = require('qs') | ||
13 | + , parse = require('../utils').parseUrl; | ||
14 | + | ||
15 | +/** | ||
16 | + * Query: | ||
17 | + * | ||
18 | + * Automatically parse the query-string when available, | ||
19 | + * populating the `req.query` object. | ||
20 | + * | ||
21 | + * Examples: | ||
22 | + * | ||
23 | + * connect() | ||
24 | + * .use(connect.query()) | ||
25 | + * .use(function(req, res){ | ||
26 | + * res.end(JSON.stringify(req.query)); | ||
27 | + * }); | ||
28 | + * | ||
29 | + * The `options` passed are provided to qs.parse function. | ||
30 | + * | ||
31 | + * @param {Object} options | ||
32 | + * @return {Function} | ||
33 | + * @api public | ||
34 | + */ | ||
35 | + | ||
36 | +module.exports = function query(options){ | ||
37 | + return function query(req, res, next){ | ||
38 | + if (!req.query) { | ||
39 | + req.query = ~req.url.indexOf('?') | ||
40 | + ? qs.parse(parse(req).query, options) | ||
41 | + : {}; | ||
42 | + } | ||
43 | + | ||
44 | + next(); | ||
45 | + }; | ||
46 | +}; |
1 | + | ||
2 | +/*! | ||
3 | + * Connect - responseTime | ||
4 | + * Copyright(c) 2011 TJ Holowaychuk | ||
5 | + * MIT Licensed | ||
6 | + */ | ||
7 | + | ||
8 | +/** | ||
9 | + * Reponse time: | ||
10 | + * | ||
11 | + * Adds the `X-Response-Time` header displaying the response | ||
12 | + * duration in milliseconds. | ||
13 | + * | ||
14 | + * @return {Function} | ||
15 | + * @api public | ||
16 | + */ | ||
17 | + | ||
18 | +module.exports = function responseTime(){ | ||
19 | + return function(req, res, next){ | ||
20 | + var start = new Date; | ||
21 | + | ||
22 | + if (res._responseTime) return next(); | ||
23 | + res._responseTime = true; | ||
24 | + | ||
25 | + res.on('header', function(){ | ||
26 | + var duration = new Date - start; | ||
27 | + res.setHeader('X-Response-Time', duration + 'ms'); | ||
28 | + }); | ||
29 | + | ||
30 | + next(); | ||
31 | + }; | ||
32 | +}; |
1 | + | ||
2 | +/*! | ||
3 | + * Connect - session | ||
4 | + * Copyright(c) 2010 Sencha Inc. | ||
5 | + * Copyright(c) 2011 TJ Holowaychuk | ||
6 | + * MIT Licensed | ||
7 | + */ | ||
8 | + | ||
9 | +/** | ||
10 | + * Module dependencies. | ||
11 | + */ | ||
12 | + | ||
13 | +var Session = require('./session/session') | ||
14 | + , debug = require('debug')('connect:session') | ||
15 | + , MemoryStore = require('./session/memory') | ||
16 | + , signature = require('cookie-signature') | ||
17 | + , Cookie = require('./session/cookie') | ||
18 | + , Store = require('./session/store') | ||
19 | + , utils = require('./../utils') | ||
20 | + , parse = utils.parseUrl | ||
21 | + , crc16 = require('crc').crc16; | ||
22 | + | ||
23 | +// environment | ||
24 | + | ||
25 | +var env = process.env.NODE_ENV; | ||
26 | + | ||
27 | +/** | ||
28 | + * Expose the middleware. | ||
29 | + */ | ||
30 | + | ||
31 | +exports = module.exports = session; | ||
32 | + | ||
33 | +/** | ||
34 | + * Expose constructors. | ||
35 | + */ | ||
36 | + | ||
37 | +exports.Store = Store; | ||
38 | +exports.Cookie = Cookie; | ||
39 | +exports.Session = Session; | ||
40 | +exports.MemoryStore = MemoryStore; | ||
41 | + | ||
42 | +/** | ||
43 | + * Warning message for `MemoryStore` usage in production. | ||
44 | + */ | ||
45 | + | ||
46 | +var warning = 'Warning: connection.session() MemoryStore is not\n' | ||
47 | + + 'designed for a production environment, as it will leak\n' | ||
48 | + + 'memory, and will not scale past a single process.'; | ||
49 | + | ||
50 | +/** | ||
51 | + * Session: | ||
52 | + * | ||
53 | + * Setup session store with the given `options`. | ||
54 | + * | ||
55 | + * Session data is _not_ saved in the cookie itself, however | ||
56 | + * cookies are used, so we must use the [cookieParser()](cookieParser.html) | ||
57 | + * middleware _before_ `session()`. | ||
58 | + * | ||
59 | + * Examples: | ||
60 | + * | ||
61 | + * connect() | ||
62 | + * .use(connect.cookieParser()) | ||
63 | + * .use(connect.session({ secret: 'keyboard cat', key: 'sid', cookie: { secure: true }})) | ||
64 | + * | ||
65 | + * Options: | ||
66 | + * | ||
67 | + * - `key` cookie name defaulting to `connect.sid` | ||
68 | + * - `store` session store instance | ||
69 | + * - `secret` session cookie is signed with this secret to prevent tampering | ||
70 | + * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }` | ||
71 | + * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto") | ||
72 | + * | ||
73 | + * Cookie option: | ||
74 | + * | ||
75 | + * By default `cookie.maxAge` is `null`, meaning no "expires" parameter is set | ||
76 | + * so the cookie becomes a browser-session cookie. When the user closes the | ||
77 | + * browser the cookie (and session) will be removed. | ||
78 | + * | ||
79 | + * ## req.session | ||
80 | + * | ||
81 | + * To store or access session data, simply use the request property `req.session`, | ||
82 | + * which is (generally) serialized as JSON by the store, so nested objects | ||
83 | + * are typically fine. For example below is a user-specific view counter: | ||
84 | + * | ||
85 | + * connect() | ||
86 | + * .use(connect.favicon()) | ||
87 | + * .use(connect.cookieParser()) | ||
88 | + * .use(connect.session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }})) | ||
89 | + * .use(function(req, res, next){ | ||
90 | + * var sess = req.session; | ||
91 | + * if (sess.views) { | ||
92 | + * res.setHeader('Content-Type', 'text/html'); | ||
93 | + * res.write('<p>views: ' + sess.views + '</p>'); | ||
94 | + * res.write('<p>expires in: ' + (sess.cookie.maxAge / 1000) + 's</p>'); | ||
95 | + * res.end(); | ||
96 | + * sess.views++; | ||
97 | + * } else { | ||
98 | + * sess.views = 1; | ||
99 | + * res.end('welcome to the session demo. refresh!'); | ||
100 | + * } | ||
101 | + * } | ||
102 | + * )).listen(3000); | ||
103 | + * | ||
104 | + * ## Session#regenerate() | ||
105 | + * | ||
106 | + * To regenerate the session simply invoke the method, once complete | ||
107 | + * a new SID and `Session` instance will be initialized at `req.session`. | ||
108 | + * | ||
109 | + * req.session.regenerate(function(err){ | ||
110 | + * // will have a new session here | ||
111 | + * }); | ||
112 | + * | ||
113 | + * ## Session#destroy() | ||
114 | + * | ||
115 | + * Destroys the session, removing `req.session`, will be re-generated next request. | ||
116 | + * | ||
117 | + * req.session.destroy(function(err){ | ||
118 | + * // cannot access session here | ||
119 | + * }); | ||
120 | + * | ||
121 | + * ## Session#reload() | ||
122 | + * | ||
123 | + * Reloads the session data. | ||
124 | + * | ||
125 | + * req.session.reload(function(err){ | ||
126 | + * // session updated | ||
127 | + * }); | ||
128 | + * | ||
129 | + * ## Session#save() | ||
130 | + * | ||
131 | + * Save the session. | ||
132 | + * | ||
133 | + * req.session.save(function(err){ | ||
134 | + * // session saved | ||
135 | + * }); | ||
136 | + * | ||
137 | + * ## Session#touch() | ||
138 | + * | ||
139 | + * Updates the `.maxAge` property. Typically this is | ||
140 | + * not necessary to call, as the session middleware does this for you. | ||
141 | + * | ||
142 | + * ## Session#cookie | ||
143 | + * | ||
144 | + * Each session has a unique cookie object accompany it. This allows | ||
145 | + * you to alter the session cookie per visitor. For example we can | ||
146 | + * set `req.session.cookie.expires` to `false` to enable the cookie | ||
147 | + * to remain for only the duration of the user-agent. | ||
148 | + * | ||
149 | + * ## Session#maxAge | ||
150 | + * | ||
151 | + * Alternatively `req.session.cookie.maxAge` will return the time | ||
152 | + * remaining in milliseconds, which we may also re-assign a new value | ||
153 | + * to adjust the `.expires` property appropriately. The following | ||
154 | + * are essentially equivalent | ||
155 | + * | ||
156 | + * var hour = 3600000; | ||
157 | + * req.session.cookie.expires = new Date(Date.now() + hour); | ||
158 | + * req.session.cookie.maxAge = hour; | ||
159 | + * | ||
160 | + * For example when `maxAge` is set to `60000` (one minute), and 30 seconds | ||
161 | + * has elapsed it will return `30000` until the current request has completed, | ||
162 | + * at which time `req.session.touch()` is called to reset `req.session.maxAge` | ||
163 | + * to its original value. | ||
164 | + * | ||
165 | + * req.session.cookie.maxAge; | ||
166 | + * // => 30000 | ||
167 | + * | ||
168 | + * Session Store Implementation: | ||
169 | + * | ||
170 | + * Every session store _must_ implement the following methods | ||
171 | + * | ||
172 | + * - `.get(sid, callback)` | ||
173 | + * - `.set(sid, session, callback)` | ||
174 | + * - `.destroy(sid, callback)` | ||
175 | + * | ||
176 | + * Recommended methods include, but are not limited to: | ||
177 | + * | ||
178 | + * - `.length(callback)` | ||
179 | + * - `.clear(callback)` | ||
180 | + * | ||
181 | + * For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo. | ||
182 | + * | ||
183 | + * @param {Object} options | ||
184 | + * @return {Function} | ||
185 | + * @api public | ||
186 | + */ | ||
187 | + | ||
188 | +function session(options){ | ||
189 | + var options = options || {} | ||
190 | + , key = options.key || 'connect.sid' | ||
191 | + , store = options.store || new MemoryStore | ||
192 | + , cookie = options.cookie || {} | ||
193 | + , trustProxy = options.proxy | ||
194 | + , storeReady = true; | ||
195 | + | ||
196 | + // notify user that this store is not | ||
197 | + // meant for a production environment | ||
198 | + if ('production' == env && store instanceof MemoryStore) { | ||
199 | + console.warn(warning); | ||
200 | + } | ||
201 | + | ||
202 | + // generates the new session | ||
203 | + store.generate = function(req){ | ||
204 | + req.sessionID = utils.uid(24); | ||
205 | + req.session = new Session(req); | ||
206 | + req.session.cookie = new Cookie(cookie); | ||
207 | + }; | ||
208 | + | ||
209 | + store.on('disconnect', function(){ storeReady = false; }); | ||
210 | + store.on('connect', function(){ storeReady = true; }); | ||
211 | + | ||
212 | + return function session(req, res, next) { | ||
213 | + // self-awareness | ||
214 | + if (req.session) return next(); | ||
215 | + | ||
216 | + // Handle connection as if there is no session if | ||
217 | + // the store has temporarily disconnected etc | ||
218 | + if (!storeReady) return debug('store is disconnected'), next(); | ||
219 | + | ||
220 | + // pathname mismatch | ||
221 | + if (0 != req.originalUrl.indexOf(cookie.path || '/')) return next(); | ||
222 | + | ||
223 | + // backwards compatibility for signed cookies | ||
224 | + // req.secret is passed from the cookie parser middleware | ||
225 | + var secret = options.secret || req.secret; | ||
226 | + | ||
227 | + // ensure secret is available or bail | ||
228 | + if (!secret) throw new Error('`secret` option required for sessions'); | ||
229 | + | ||
230 | + // parse url | ||
231 | + var url = parse(req) | ||
232 | + , path = url.pathname | ||
233 | + , originalHash | ||
234 | + , originalId; | ||
235 | + | ||
236 | + // expose store | ||
237 | + req.sessionStore = store; | ||
238 | + | ||
239 | + // grab the session cookie value and check the signature | ||
240 | + var rawCookie = req.cookies[key]; | ||
241 | + | ||
242 | + // get signedCookies for backwards compat with signed cookies | ||
243 | + var unsignedCookie = req.signedCookies[key]; | ||
244 | + | ||
245 | + if (!unsignedCookie && rawCookie) { | ||
246 | + unsignedCookie = utils.parseSignedCookie(rawCookie, secret); | ||
247 | + } | ||
248 | + | ||
249 | + // set-cookie | ||
250 | + res.on('header', function(){ | ||
251 | + if (!req.session) return; | ||
252 | + var cookie = req.session.cookie | ||
253 | + , proto = (req.headers['x-forwarded-proto'] || '').toLowerCase() | ||
254 | + , tls = req.connection.encrypted || (trustProxy && 'https' == proto) | ||
255 | + , secured = cookie.secure && tls | ||
256 | + , isNew = unsignedCookie != req.sessionID; | ||
257 | + | ||
258 | + // only send secure cookies via https | ||
259 | + if (cookie.secure && !secured) return debug('not secured'); | ||
260 | + | ||
261 | + // browser-session length cookie | ||
262 | + if (null == cookie.expires) { | ||
263 | + if (!isNew) return debug('already set browser-session cookie'); | ||
264 | + // compare hashes and ids | ||
265 | + } else if (originalHash == hash(req.session) && originalId == req.session.id) { | ||
266 | + return debug('unmodified session'); | ||
267 | + } | ||
268 | + | ||
269 | + var val = 's:' + signature.sign(req.sessionID, secret); | ||
270 | + val = cookie.serialize(key, val); | ||
271 | + debug('set-cookie %s', val); | ||
272 | + res.setHeader('Set-Cookie', val); | ||
273 | + }); | ||
274 | + | ||
275 | + // proxy end() to commit the session | ||
276 | + var end = res.end; | ||
277 | + res.end = function(data, encoding){ | ||
278 | + res.end = end; | ||
279 | + if (!req.session) return res.end(data, encoding); | ||
280 | + debug('saving'); | ||
281 | + req.session.resetMaxAge(); | ||
282 | + req.session.save(function(){ | ||
283 | + debug('saved'); | ||
284 | + res.end(data, encoding); | ||
285 | + }); | ||
286 | + }; | ||
287 | + | ||
288 | + // generate the session | ||
289 | + function generate() { | ||
290 | + store.generate(req); | ||
291 | + } | ||
292 | + | ||
293 | + // get the sessionID from the cookie | ||
294 | + req.sessionID = unsignedCookie; | ||
295 | + | ||
296 | + // generate a session if the browser doesn't send a sessionID | ||
297 | + if (!req.sessionID) { | ||
298 | + debug('no SID sent, generating session'); | ||
299 | + generate(); | ||
300 | + next(); | ||
301 | + return; | ||
302 | + } | ||
303 | + | ||
304 | + // generate the session object | ||
305 | + var pause = utils.pause(req); | ||
306 | + debug('fetching %s', req.sessionID); | ||
307 | + store.get(req.sessionID, function(err, sess){ | ||
308 | + // proxy to resume() events | ||
309 | + var _next = next; | ||
310 | + next = function(err){ | ||
311 | + _next(err); | ||
312 | + pause.resume(); | ||
313 | + } | ||
314 | + | ||
315 | + // error handling | ||
316 | + if (err) { | ||
317 | + debug('error'); | ||
318 | + if ('ENOENT' == err.code) { | ||
319 | + generate(); | ||
320 | + next(); | ||
321 | + } else { | ||
322 | + next(err); | ||
323 | + } | ||
324 | + // no session | ||
325 | + } else if (!sess) { | ||
326 | + debug('no session found'); | ||
327 | + generate(); | ||
328 | + next(); | ||
329 | + // populate req.session | ||
330 | + } else { | ||
331 | + debug('session found'); | ||
332 | + store.createSession(req, sess); | ||
333 | + originalId = req.sessionID; | ||
334 | + originalHash = hash(sess); | ||
335 | + next(); | ||
336 | + } | ||
337 | + }); | ||
338 | + }; | ||
339 | +}; | ||
340 | + | ||
341 | +/** | ||
342 | + * Hash the given `sess` object omitting changes | ||
343 | + * to `.cookie`. | ||
344 | + * | ||
345 | + * @param {Object} sess | ||
346 | + * @return {String} | ||
347 | + * @api private | ||
348 | + */ | ||
349 | + | ||
350 | +function hash(sess) { | ||
351 | + return crc16(JSON.stringify(sess, function(key, val){ | ||
352 | + if ('cookie' != key) return val; | ||
353 | + })); | ||
354 | +} |
635 Bytes
739 Bytes
794 Bytes
818 Bytes
663 Bytes
740 Bytes
807 Bytes
793 Bytes
817 Bytes
879 Bytes
833 Bytes
779 Bytes
621 Bytes
801 Bytes
839 Bytes
830 Bytes
813 Bytes
703 Bytes
641 Bytes
858 Bytes
774 Bytes
294 Bytes
591 Bytes
664 Bytes
512 Bytes
587 Bytes
656 Bytes
666 Bytes
603 Bytes
587 Bytes
592 Bytes
724 Bytes
309 Bytes
621 Bytes
700 Bytes
639 Bytes
579 Bytes
536 Bytes
638 Bytes
618 Bytes
623 Bytes
663 Bytes
676 Bytes
582 Bytes
639 Bytes
402 Bytes
516 Bytes
612 Bytes
603 Bytes
296 Bytes
616 Bytes
669 Bytes
614 Bytes
554 Bytes
706 Bytes
779 Bytes
688 Bytes
618 Bytes
620 Bytes
538 Bytes
650 Bytes
588 Bytes
523 Bytes
626 Bytes
317 Bytes
565 Bytes
634 Bytes
342 Bytes
315 Bytes
668 Bytes
644 Bytes
702 Bytes
309 Bytes
651 Bytes
734 Bytes
613 Bytes
386 Bytes
777 Bytes
903 Bytes
-
Please register or login to post a comment