├── .env.example ├── .gitignore ├── LICENSE ├── Procfile ├── README.md ├── camel.js ├── nodemon.json ├── npm-shrinkwrap.json ├── package.json ├── posts ├── 2014 │ └── 5 │ │ └── 1 │ │ └── sample-post.md ├── 2015 │ └── 2 │ │ ├── 6 │ │ └── sample-link-post.md │ │ └── 16 │ │ └── some-awesome-website.redirect ├── 404.md ├── about.md └── index.md ├── public └── css │ └── site.css ├── templates ├── defaultTags.html ├── footer.html ├── header.html ├── postHeader.html └── rssFooter.html └── typings ├── body-parser └── body-parser.d.ts ├── express └── express.d.ts ├── handlebars └── handlebars.d.ts ├── node └── node.d.ts ├── q-io └── Q-io.d.ts ├── sugar └── sugar.d.ts └── underscore └── underscore.d.ts /.env.example: -------------------------------------------------------------------------------- 1 | [Cameljs App] 2 | PORT= 3 | 4 | [Drafts] 5 | AUTH_USER_NAME= 6 | AUTH_PASSWORD= 7 | 8 | [Twitter Access] 9 | TWITTER_CONSUMER_KEY= 10 | TWITTER_CONSUMER_SECRET= 11 | TWITTER_ACCESS_TOKEN= 12 | TWITTER_TOKEN_SECRET= 13 | 14 | [Twitter Display] 15 | TWITTER_USERNAME= 16 | TWITTER_CLIENT_NEEDLE= 17 | 18 | 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Dependencies 11 | node_modules 12 | 13 | # env variables 14 | .env 15 | 16 | # Mac artifacts 17 | .DS_Store 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Casey Liss 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. 22 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: node camel.js 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | "Camel" is a blogging platform written in [Node.js][n]. It is designed to be fast, simple, and lean. 2 | 3 | [n]: http://nodejs.org/ 4 | 5 | # Design Goals 6 | 7 | More specifically, the design goals were: 8 | 9 | * Easy posting using [Markdown][m] 10 | * Basic metadata, stored in each file 11 | * Basic templating, with a site header/footer and post header stored separately from content 12 | * Extremely quick performance, by caching rendered HTML output 13 | * Support for two RSS feeds: 14 | * The default one, where link posts open on the target website 15 | * The alternate feed, where link posts open on this website 16 | * Optional automatic posts to Twitter 17 | 18 | [m]: http://daringfireball.net/projects/markdown 19 | 20 | # Approach 21 | 22 | Camel is neither a static blogging platform nor a truly dynamic one. It is a little 23 | from column A, and a little from column B. The first time a post is loaded, it is rendered 24 | by converting from Markdown to HTML, and then postprocessed by adding headers & footer, as well 25 | as making metadata replacements. Upon a completed render, the resultant HTML is stored 26 | and used from that point forward. 27 | 28 | # Usage 29 | 30 | ## Installation 31 | 32 | 1. Install [Node][n] & [npm][npm] 33 | 2. Clone the repository 34 | 3. Get all the dependencies using NPM: `npm install` 35 | 4. `node ./camel.js` or using `npm start` 36 | 37 | [npm]: https://www.npmjs.org/ 38 | 39 | ## Configuration 40 | 41 | * There's a group of "statics" near the top of the file 42 | * The RSS parameters in the `generateRss` function will need to be modified. 43 | * The headers/footers: 44 | * `header.html` - site header; shown at the top of every page 45 | * `footer.html` - site footer; shown at the bottom of every page 46 | * `defaultTags.html` - default metadata; merged with page metadata (page wins) 47 | * `postHeader.html` - post header; shown at the top of every post not marked with `@@ HideHeader=true`. See below. 48 | * `rssFooter.html` - RSS footer; intended to only show anything on the bottom of 49 | link posts in RSS, but is appended to all RSS entries. 50 | * It's worth noting there are some [Handlebars][hb] templates in use: 51 | * `index.md` 52 | * `@@ DayTemplate` - used to render a day 53 | * `@@ ArticlePartial` – used to render a single article in a day 54 | * `@@ FooterTemplate` - used to render pagination 55 | * `postHeader.html` - placed on every post between the site header and post content 56 | * `rssFooter.html` - placed on the bottom of every RSS item 57 | * If you'd like to have Camel post to Twitter, set four environment variables (see below) 58 | * If you'd like to support endpoints that require [basic auth](https://en.wikipedia.org/wiki/Basic_access_authentication), 59 | set two environment variables (see below). 60 | 61 | [hb]: http://handlebarsjs.com/ 62 | 63 | ### Environment Variables 64 | 65 | You can define ENV variables used by Camel in one of the following ways: 66 | 67 | 1. Heroku admin panel 68 | 2. `export` function in bash/zsh shells. 69 | 3. `.env` file - use `.env.example` as a starting point 70 | 71 | ## Files 72 | 73 | To use Camel, the following files are required: 74 | 75 | Root 76 | +-- camel.js 77 | | Application entry point 78 | +-- package.json 79 | | Node package file 80 | +-- templates/ 81 | | +-- defaultTags.html 82 | | | Site-level default tags, such as the site title 83 | | +-- header.html 84 | | | Site header (top of every page) 85 | | +-- footer.html 86 | | | Site footer (bottom of every page) 87 | | +-- postHeader.html 88 | | | Post header (top of every post, after the site header. Handlebars template.) 89 | | `-- rssFooter.html 90 | | RSS footer (at the end of every RSS item) 91 | +-- public/ 92 | | `-- Any static files, such as images/css/javascript/etc. 93 | `-- posts/ 94 | All the pages & posts are here. Pages in the root, posts ordered by day. For example: 95 | +-- index.md 96 | | Root file; note that DayTemplate, ArticlePartial, and FooterTemplate are 97 | | all Handlebars templates 98 | +-- about.md 99 | | Sample about page 100 | +-- 2014/ 101 | | Year 102 | | +-- 4/ 103 | | | Month 104 | | | +-- 29/ 105 | | | | Day 106 | | | | `-- some-blog-post.md 107 | | | `-- 30/ 108 | | | +-- some-other-post.md 109 | | | `-- yet-another-post.md 110 | | `-- 5/ 111 | | +-- 1/ 112 | | | `-- newest-blog-post.md 113 | | `-- 5/ 114 | | `-- some-cool-website.redirect 115 | `-- etc. 116 | 117 | For each post, metadata is specified at the top, and can be leveraged in the body. For example: 118 | 119 | @@ Title=Test Post 120 | @@ Date=2014-05 17:50 121 | @@ Description=This is a short description used in Twitter cards and Facebook Open Graph. 122 | @@ Image=http://somehost.com/someimage.png 123 | 124 | This is a *test post* entitled "@@Title@@". 125 | 126 | The title and date are required. Any other metadata, such as `Description` and `Image`, is optional. 127 | 128 | As of version 1.5.3, you can optionally use 129 | [MultiMarkdown-style metadata](http://fletcher.github.io/MultiMarkdown-5/syntax.html#metadata). 130 | If you choose to use that style, the above would be: 131 | 132 | Title: Test Post 133 | Date: 2014-05 17:50 134 | Description: This is a short description used in Twitter cards and Facebook Open Graph. 135 | Image: http://somehost.com/someimage.png 136 | 137 | This is a *test post* entitled "@@Title@@". 138 | 139 | Note, however, that MultiMarkdown's support for multiline metadata is not supported. 140 | Each metadata item must be wholly contained on its own line. 141 | 142 | ### Link Posts 143 | As of version 1.3, link posts are supported. To create a link post, simply add a `Link` 144 | metadata item: 145 | 146 | @@ Title=Sample Link Post 147 | @@ Date=2015-02-06 12:00 148 | @@ Link=http://www.vt.edu/ 149 | 150 | This is a sample *link* post. 151 | 152 | The presence of a `Link` metadata item indicates this is a link post. The formatting for 153 | link and non-link post headers is controlled by the `postHeader.html` template. 154 | 155 | In the RSS feed, the link for a link post is the *external* link. Thus, `rssFooter.html` 156 | is used to add a permalink to the Camel site at the bottom of each link post. It is 157 | important to note that this footer is shown on *every* post; it is up to the footer to 158 | decide whether or not to show anything for the post in question. The example included in 159 | this repo behaves as intended. 160 | 161 | ### Redirects 162 | 163 | As of version 1.1, redirects are supported. To do so, a specially formed file is placed 164 | in the `posts/` tree. The file should have two lines; the first should be the status code 165 | of the redirect ([301][301] or [302][302]). The second line should be the target URL. 166 | 167 | Suppose you wanted to redirect `/2014/12/10/source` to `/2014/12/10/destination`. You will 168 | add the file `/posts/2014/12/10/source.redirect`; it will contain the following: 169 | 170 | 302 171 | /2014/12/10/destination 172 | 173 | Redirects to both internal and external URLs are supported. Providing an invalid status 174 | code will result in that status code being used blindly, so tread carefully. 175 | 176 | [301]: http://en.wikipedia.org/wiki/HTTP_301 177 | [302]: http://en.wikipedia.org/wiki/HTTP_302 178 | 179 | ### Automatic tweets 180 | 181 | As of version 1.4, Camel can automatically tweet when a new post is discovered. This 182 | requires a custom app to be set up for your blog; you can set this up [at Twitter][tdev]. 183 | To enable, specify four environment variables to correspond to those Twitter issues: 184 | 185 | * `TWITTER_CONSUMER_KEY` 186 | * `TWITTER_CONSUMER_SECRET` 187 | * `TWITTER_ACCESS_TOKEN` 188 | * `TWITTER_TOKEN_SECRET` 189 | 190 | Additionally, a couple of variables up at the top of the file need to be set: 191 | 192 | * `twitterUsername` - the username of the Twitter account that will be tweeted from. 193 | * `twitterClientNeedle` - a portion of the client's name 194 | 195 | Upon startup, and when the caches are cleaned, Camel will look at the most recent tweets 196 | by the account in question by the app with a name that contains `twitterClientNeedle`. It 197 | will look to see the most recent URL tweeted. If the URL does not match the most recent 198 | post's URL, then a tweet is fired off. 199 | 200 | [tdev]: https://apps.twitter.com 201 | 202 | ### Authentication 203 | 204 | As of version 1.5.0, basic authentication is supported. It is selectively used on individual 205 | routes in order to provide a small barrier for entry for administrative tasks, most 206 | specifically, rendering a draft post. Naturally, basic auth is an inherently insecure 207 | protection mechanism; it is provided simply to prevent drive-bys. 208 | 209 | To enable basic authentication, two environment variables are required: 210 | 211 | * `AUTH_USER_NAME` 212 | * `AUTH_PASSWORD` 213 | 214 | By default, the `/render-draft` endpoint requires basic auth to actually render a draft 215 | post. 216 | 217 | 218 | # Quirks 219 | 220 | There are a couple of quirks, which don't bother me, but may bother you. 221 | 222 | ## Adding a Post 223 | 224 | When a new post is created, if you want an instant refresh, you'll want to restart the 225 | app in order to clear the caches. There is a commented out route `/tosscache` that will also 226 | do this job, if you choose to enable it. 227 | 228 | Otherwise, the internal caches will reset every 30 minutes. 229 | 230 | Additionally, there is no mechanism within Camel for transporting a post to the `posts/` 231 | directory. It is assumed that delivery will happen by way of a `git push` or equivalent. 232 | That is, for example, how it would work when run on [Heroku][h]. 233 | 234 | *Note that as of 19 November 2014, Heroku now supports integration with Dropbox, which 235 | [makes it much easier to post to Camel while mobile][camelmobile].* 236 | 237 | [h]: http://www.heroku.com/ 238 | [camelmobile]: http://www.caseyliss.com/2014/11/19/heroku-adds-dropbox-support 239 | 240 | ## Pagination 241 | 242 | Camel uses a semi-peculiar pagination model which is being referred to as "loose pagination". 243 | Partly due to laziness, and partly because it seems better, pagination isn't strict. Rather 244 | than always cutting off a page after N posts, instead, pagination is handled differently. 245 | 246 | Starting with the most recent day's posts, all the posts in that day are added to a logical 247 | page. Once that page contains N *or more* posts, that page is considered complete. The next 248 | page is then started. 249 | 250 | Therefore, all the posts in a single day will __always__ be on the same page. That, in turns, means 251 | that pages will have *at least* N posts, but possibly more. In fact, a single page could have 252 | quite a few more than N posts if, say, on one lucrative day there are 1.5*N or 2*N posts. 253 | 254 | Pagination is only necessary on the homepage, and page numbers are 1-based. Pages greater than 255 | 1 are loaded by passing the query string parameter p. For example, `hostname/page/3` for page 3. 256 | 257 | # Status 258 | 259 | Camel is functional, and is presently running [www.caseyliss.com][c]. There are lots of 260 | features that probably *could* be added, but none that I'm actively planning. 261 | 262 | [c]: http://www.caseyliss.com/ 263 | 264 | ## Branches 265 | 266 | There is a branch, [`postuploads`][pu], that allows for posts to be uploaded via the same 267 | mechanism as making a draft. This isn't useful for [www.caseyliss.com][c], due to the way 268 | that Camel is hosted, but may be useful for others. 269 | 270 | [pu]: https://github.com/cliss/camel/tree/postuploads 271 | 272 | # License 273 | 274 | Camel is MIT-Licensed. 275 | 276 | While by no means neccessary, I'd very much appreciate it if you provided a link back to 277 | either this repository, or [my website][c], on any sites that run Camel. 278 | 279 | # Change Log 280 | 281 | * __1.5.7__ Fix bug wherein RSS caching could get confused if multiple hostnames are 282 | used to access the site. 283 | * __1.5.6__ Fix bug wherein a `Description` that contains a `"` would not be escaped, and 284 | thus would prematurely truncate `twitter:description` and `og:descripton` tags. 285 | * __1.5.5__ Fix bug in `/render-draft` where each line had a double carriage return. This 286 | caused metadata to not be picked up properly, and thus the post not render properly. 287 | In turn, that defeated most of the purpose of draft support in the first place. 288 | * __1.5.4__ Fix bug wherein a MultiMarkdown-style metadata line that contained a URL with a 289 | query string caused a crash. 290 | * __1.5.3__ Adds support for 291 | [MultiMarkdown-style metadata](http://fletcher.github.io/MultiMarkdown-5/syntax.html#metadata). 292 | Previous-style metadata (prefix with `@@`) is still supported. 293 | * __1.5.2__ Prevent display of posts dated in the future. 294 | * __1.5.1__ Add ability to define ENV variables using a `.env` file. 295 | * __1.5.0__ Add `/render-draft` route with basic authentication. 296 | * __1.4.8__ Fix broken auto-tweeter. 297 | * __1.4.7__ Tweak postRegex to allow for posts that have trailing `+` in their name, such 298 | as [this one](http://www.caseyliss.com/2014/10/2/emoji++) 299 | * __1.4.6__ Change deep homepage pages to `/page/N` instead of `/?p=N`. Maintains support for 300 | original, query string based URLs. Upgrade to latest version of packages. 301 | * __1.4.5__ Fix auto-tweeter not considering too-long titles 302 | (issue #[21](https://github.com/cliss/camel/issues/21)) 303 | * __1.4.4__ Add support for Facebook Open Graph. 304 | * __1.4.3__ Add support for Twitter cards; thanks to [@tofias](https://twitter.com/tofias) 305 | for the help. 306 | * __1.4.2__ Now provides for `/rss-alternate`, which points link posts to internal links 307 | instead of external ones. 308 | * __1.4.1__ Refactored to satisfy [JSLint](http://jslint.it). Fixed issue where a day that 309 | only had a redirect in it caused duplicate day breaks to show on the homepage. 310 | * __1.4.0__ Added support for auto-tweeting. 311 | * __1.3.1__ Updated RSS feed such that link posts open the external link, and have a 312 | "Permalink" to the site is shown at the bottom of the post. 313 | * __1.3.0__ Added link posts. 314 | * __1.2.1__ Significant cleanup/restructuring. Now less embarrassing! Removal of lots of 315 | similar-sounding functions and more liberal use of data that we've already collected in 316 | `allPostsSortedAndGrouped()`. 317 | * __1.2.0__ Changes from [marked](https://github.com/chjj/marked) to 318 | [markdown-it](https://github.com/markdown-it/markdown-it), adds support for footnotes. 319 | * __1.1.0__ Fix post regex issue, adds support for redirects, adds `/count` route, 320 | prevents year responses for unreasonable years 321 | * __1.0.1__ Adds x-powered-by header, upgrades to packages 322 | * __1.0.0__ Initial release 323 | -------------------------------------------------------------------------------- /camel.js: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | /// 7 | /// 8 | 9 | /*************************************************** 10 | * INITIALIZATION * 11 | ***************************************************/ 12 | 13 | // load ENV variables from .env file 14 | // use .env.example file as a starting point 15 | require('dotenv').load({silent: true}); 16 | 17 | var express = require('express'); 18 | var bodyParser = require('body-parser'); 19 | var compress = require('compression'); 20 | var http = require('http'); 21 | var fs = require('fs'); 22 | var qfs = require('q-io/fs'); 23 | var sugar = require('sugar'); 24 | var _ = require('underscore'); 25 | var markdownit = require('markdown-it')({ 26 | html: true, 27 | xhtmlOut: true, 28 | typographer: true 29 | }).use(require('markdown-it-footnote')); 30 | var Rss = require('rss'); 31 | var Handlebars = require('handlebars'); 32 | var version = require('./package.json').version; 33 | var Twitter = require('twitter'); 34 | var basicAuth = require('basic-auth'); 35 | var twitterClient = new Twitter({ 36 | consumer_key: process.env.TWITTER_CONSUMER_KEY, 37 | consumer_secret: process.env.TWITTER_CONSUMER_SECRET, 38 | access_token_key: process.env.TWITTER_ACCESS_TOKEN, 39 | access_token_secret: process.env.TWITTER_TOKEN_SECRET 40 | }); 41 | var draftAuthInfo = { 42 | user: process.env.AUTH_USER_NAME, 43 | pass: process.env.AUTH_PASSWORD 44 | }; 45 | 46 | var app = express(); 47 | app.use(compress()); 48 | app.use(express.static("public")); 49 | app.use(function (request, response, next) { 50 | response.header('X-powered-by', 'Camel (https://github.com/cliss/camel)'); 51 | next(); 52 | }); 53 | var server = http.createServer(app); 54 | 55 | // "Statics" 56 | var postsRoot = './posts/'; 57 | var templateRoot = './templates/'; 58 | var metadataMarker = '@@'; 59 | var maxCacheSize = 50; 60 | var postsPerPage = 10; 61 | var postRegex = /^(.\/)?posts\/\d{4}\/\d{1,2}\/\d{1,2}\/(\w|-|\+)*(.redirect|.md)?$/; 62 | var footnoteAnchorRegex = /[#"]fn\d+/g; 63 | var footnoteIdRegex = /fnref\d+/g; 64 | var utcOffset = 5; 65 | var cacheResetTimeInMillis = 1800000; 66 | var twitterUsername = process.env.TWITTER_USERNAME; // 'caseylisscom'; 67 | var twitterClientNeedle = process.env.TWITTER_CLIENT_NEEDLE; //'Camel Spitter'; 68 | 69 | var renderedPosts = {}; 70 | 71 | /* { 72 | * hostone.website.com: { 73 | * date: "" 74 | * rss: "" 75 | * }, 76 | * hosttwo.website.com: { 77 | * date: "" 78 | * rss: "" 79 | * } 80 | * ] 81 | */ 82 | var renderedRss = {}; 83 | var renderedAlternateRss = {}; 84 | var allPostsSortedGrouped = {}; 85 | var headerSource; 86 | var footerSource = null; 87 | var postHeaderTemplate = null; 88 | var rssFooterTemplate = null; 89 | var siteMetadata = {}; 90 | 91 | /*************************************************** 92 | * HELPER METHODS * 93 | ***************************************************/ 94 | 95 | // Middleware to require auth for routes 96 | function requireAuth(request, response, next) { 97 | if (Object.values(draftAuthInfo).all(function (i) { typeof i !== 'undefined' && i.length > 0; })) { 98 | var user = basicAuth(request); 99 | 100 | if (!user || user.name !== draftAuthInfo.user || user.pass !== draftAuthInfo.pass) { 101 | response.set('WWW-Authenticate', 'Basic realm=Authorization Required'); 102 | return response.status(401).send('You have to say the magic word.'); 103 | } 104 | } 105 | next(); 106 | }; 107 | 108 | function normalizedFileName(file) { 109 | var retVal = file; 110 | if (file.startsWith('posts')) { 111 | retVal = './' + file; 112 | } 113 | 114 | retVal = retVal.replace('.md', ''); 115 | 116 | return retVal; 117 | } 118 | 119 | function fetchFromCache(file) { 120 | return renderedPosts[normalizedFileName(file)] || null; 121 | } 122 | 123 | function addRenderedPostToCache(file, postData) { 124 | //console.log('Adding to cache: ' + normalizedFileName(file)); 125 | renderedPosts[normalizedFileName(file)] = _.extend({ file: normalizedFileName(file), date: new Date() }, postData); 126 | 127 | if (_.size(renderedPosts) > maxCacheSize) { 128 | var sorted = _.sortBy(renderedPosts, function (post) { return post.date; }); 129 | delete renderedPosts[sorted.first().file]; 130 | } 131 | 132 | //console.log('Cache has ' + JSON.stringify(_.keys(renderedPosts))); 133 | } 134 | 135 | // Separate the metadata from the body 136 | function getLinesFromData(data) { 137 | // Drafts seem to treat carriage returns as "\r\n"; real 138 | // posts are simply "\n". Remove all the "\r"s so that 139 | // everything looks like we expect. 140 | data = data.replace(/\r/g, ''); 141 | var lines = data.lines(); 142 | // Extract the metadata 143 | var metadataEnds = _.findIndex(lines, function (line) { 144 | return line.trim().length === 0; 145 | }); 146 | metadataEnds = metadataEnds === -1 ? lines.length : metadataEnds; 147 | 148 | return { 149 | metadata: lines.slice(0, metadataEnds), 150 | body: lines.slice(metadataEnds).join('\n') 151 | }; 152 | } 153 | 154 | // Gets all the lines in a post and separates the metadata from the body 155 | function getLinesFromPost(file) { 156 | file = file.endsWith('.md') ? file : file + '.md'; 157 | var data = fs.readFileSync(file, {encoding: 'UTF8'}); 158 | 159 | return getLinesFromData(data); 160 | } 161 | 162 | // Parses the metadata in the file 163 | function parseMetadata(lines) { 164 | var retVal = {}; 165 | 166 | lines.each(function (line) { 167 | if (line.has(metadataMarker) && line.has('=')) { 168 | line = line.replace(metadataMarker, ''); 169 | line = line.compact(); 170 | var firstIndex = line.indexOf('='); 171 | retVal[line.first(firstIndex)] = line.from(firstIndex + 1); 172 | } else if (line.has(':')) { 173 | line = line.compact(); 174 | var firstIndex = line.indexOf(':'); 175 | retVal[line.first(firstIndex)] = line.from(firstIndex + 2); 176 | } 177 | }); 178 | 179 | // Description could have a " in it that needs to be escaped. 180 | if (Object.has(retVal, "Description")) { 181 | retVal["Description"] = retVal["Description"].replace(/"/g, '"') 182 | } 183 | 184 | // NOTE: Some metadata is added in generateHtmlAndMetadataForFile(). 185 | 186 | // Merge with site default metadata 187 | Object.merge(retVal, siteMetadata, false, function (key, targetVal, sourceVal) { 188 | // Ensure that the file wins over the defaults. 189 | return targetVal; 190 | }); 191 | 192 | return retVal; 193 | } 194 | 195 | // Gets the external link for this file. Relative if request is 196 | // not specified. Absolute if request is specified. 197 | function externalFilenameForFile(file, request) { 198 | var hostname = typeof(request) !== 'undefined' ? request.headers.host : ''; 199 | 200 | var retVal = hostname.length ? ('http://' + hostname) : ''; 201 | retVal += file.at(0) === '/' && hostname.length > 0 ? '' : '/'; 202 | retVal += file.replace('.md', '').replace(postsRoot, '').replace(postsRoot.replace('./', ''), ''); 203 | return retVal; 204 | } 205 | 206 | function performMetadataReplacements(replacements, haystack) { 207 | _.keys(replacements).each(function (key) { 208 | // Ensure that it's a global replacement; non-regex treatment is first-only. 209 | haystack = haystack.replace(new RegExp(metadataMarker + key + metadataMarker, 'g'), replacements[key]); 210 | }); 211 | 212 | return haystack; 213 | } 214 | 215 | function generateHtmlAndMetadataForLines(lines, file) { 216 | var metadata = parseMetadata(lines.metadata); 217 | if (typeof(file) !== 'undefined') { 218 | metadata.relativeLink = externalFilenameForFile(file); 219 | // If this is a post, assume a body class of 'post'. 220 | if (postRegex.test(file)) { 221 | metadata.BodyClass = 'post'; 222 | } 223 | } 224 | 225 | return { 226 | metadata: metadata, 227 | header: performMetadataReplacements(metadata, headerSource), 228 | postHeader: performMetadataReplacements(metadata, postHeaderTemplate(metadata)), 229 | rssFooter: performMetadataReplacements(metadata, rssFooterTemplate(metadata)), 230 | unwrappedBody: performMetadataReplacements(metadata, markdownit.render(lines.body)), 231 | html: function () { 232 | return this.header + 233 | this.postHeader + 234 | this.unwrappedBody + 235 | footerSource; 236 | } 237 | }; 238 | } 239 | 240 | // Gets the metadata & rendered HTML for this file 241 | function generateHtmlAndMetadataForFile(file) { 242 | var retVal = fetchFromCache(file); 243 | if (typeof(retVal) !== 'undefined') { 244 | var lines = getLinesFromPost(file); 245 | addRenderedPostToCache(file, generateHtmlAndMetadataForLines(lines, file)); 246 | } 247 | 248 | return fetchFromCache(file); 249 | } 250 | 251 | // Gets all the posts, grouped by day and sorted descending. 252 | // Completion handler gets called with an array of objects. 253 | // Array 254 | // +-- Object 255 | // | +-- 'date' => Date for these articles 256 | // | `-- 'articles' => Array 257 | // | +-- (Article Object) 258 | // | +-- ... 259 | // | `-- (Article Object) 260 | // + ... 261 | // | 262 | // `-- Object 263 | // +-- 'date' => Date for these articles 264 | // `-- 'articles' => Array 265 | // +-- (Article Object) 266 | // +-- ... 267 | // `-- (Article Object) 268 | function allPostsSortedAndGrouped(completion) { 269 | if (Object.size(allPostsSortedGrouped) !== 0) { 270 | completion(allPostsSortedGrouped); 271 | } else { 272 | qfs.listTree(postsRoot, function (name, stat) { 273 | return postRegex.test(name); 274 | }).then(function (files) { 275 | // Lump the posts together by day 276 | var groupedFiles = _.groupBy(files, function (file) { 277 | var parts = file.split('/'); 278 | return new Date(parts[1], parts[2] - 1, parts[3]); 279 | }); 280 | 281 | // Sort the days from newest to oldest 282 | var retVal = []; 283 | var sortedKeys = _.sortBy(_.keys(groupedFiles), function (date) { 284 | return new Date(date); 285 | }).reverse(); 286 | 287 | // For each day... 288 | _.each(sortedKeys, function (key) { 289 | if (new Date(key) > new Date()) { 290 | return; 291 | } 292 | 293 | // Get all the filenames... 294 | var articleFiles = groupedFiles[key]; 295 | var articles = []; 296 | // ...get all the data for that file ... 297 | _.each(articleFiles, function (file) { 298 | if (!file.endsWith('redirect')) { 299 | articles.push(generateHtmlAndMetadataForFile(file)); 300 | } 301 | }); 302 | 303 | // ...so we can sort the posts... 304 | articles = _.sortBy(articles, function (article) { 305 | // ...by their post date and TIME. 306 | return Date.create(article.metadata.Date); 307 | }).reverse(); 308 | // Array of objects; each object's key is the date, value 309 | // is an array of objects 310 | // In that array of objects, there is a body & metadata. 311 | // Note if this day only had a redirect, it may have no articles. 312 | if (articles.length > 0) { 313 | retVal.push({date: key, articles: articles}); 314 | } 315 | }); 316 | 317 | allPostsSortedGrouped = retVal; 318 | completion(retVal); 319 | }); 320 | } 321 | } 322 | 323 | function tweetLatestPost() { 324 | if (twitterClient !== null && typeof(process.env.TWITTER_CONSUMER_KEY) !== 'undefined') { 325 | twitterClient.get('statuses/user_timeline', {screen_name: twitterUsername}, function (error, tweets) { 326 | if (error) { 327 | console.log(JSON.stringify(error, undefined, 2)); 328 | return; 329 | } 330 | 331 | var lastUrl = null, i = 0; 332 | while (lastUrl === null && i < tweets.length) { 333 | if (tweets[i].source.has(twitterClientNeedle) && 334 | tweets[i].entities && 335 | tweets[i].entities.urls && 336 | tweets[i].entities.urls.length > 0) { 337 | lastUrl = tweets[i].entities.urls[0].expanded_url; 338 | } else { 339 | i += 1; 340 | } 341 | } 342 | 343 | allPostsSortedAndGrouped(function (postsByDay) { 344 | var latestPost = postsByDay[0].articles[0]; 345 | var link = latestPost.metadata.SiteRoot + latestPost.metadata.relativeLink; 346 | 347 | if (lastUrl !== link) { 348 | console.log('Tweeting new link: ' + link); 349 | 350 | // Figure out how many characters we have to play with. 351 | twitterClient.get('help/configuration', function (error, configuration, response) { 352 | var suffix = " \n\n"; 353 | var maxSize = 280 - configuration.short_url_length_https - suffix.length; 354 | 355 | // Shorten the title if need be. 356 | var title = latestPost.metadata.Title; 357 | if (title.length > maxSize) { 358 | title = title.substring(0, maxSize - 3) + '...'; 359 | } 360 | 361 | var params = { 362 | status: title + suffix + link 363 | }; 364 | twitterClient.post('statuses/update', params, function (error, tweet, response) { 365 | if (error) { 366 | console.log(JSON.stringify(error, undefined, 2)); 367 | } 368 | }); 369 | }); 370 | } else { 371 | console.log('Twitter is up to date.'); 372 | } 373 | }); 374 | }); 375 | } 376 | } 377 | 378 | // Loads header or footer files from disk 379 | function loadHeaderFooter(file, completion) { 380 | fs.exists(templateRoot + file, function(exists) { 381 | if (exists) { 382 | fs.readFile(templateRoot + file, {encoding: 'UTF8'}, function (error, data) { 383 | if (!error) { 384 | completion(data); 385 | } 386 | }); 387 | } 388 | }); 389 | } 390 | 391 | // Empties the caches. 392 | function emptyCache() { 393 | console.log('Emptying the cache.'); 394 | renderedPosts = {}; 395 | renderedRss = {}; 396 | allPostsSortedGrouped = {}; 397 | 398 | tweetLatestPost(); 399 | } 400 | 401 | // Initialize application and load template files 402 | function init() { 403 | loadHeaderFooter('defaultTags.html', function (data) { 404 | // Note this comes in as a flat string; split on newlines for parsing metadata. 405 | siteMetadata = parseMetadata(data.split('\n')); 406 | 407 | // This relies on the above, so nest it. 408 | loadHeaderFooter('header.html', function (data) { 409 | headerSource = data; 410 | }); 411 | }); 412 | loadHeaderFooter('footer.html', function (data) { footerSource = data; }); 413 | loadHeaderFooter('rssFooter.html', function (data) { 414 | rssFooterTemplate = Handlebars.compile(data); 415 | }); 416 | loadHeaderFooter('postHeader.html', function (data) { 417 | Handlebars.registerHelper('formatPostDate', function (date) { 418 | return new Handlebars.SafeString(new Date(date).format('{Weekday}, {d} {Month} {yyyy}')); 419 | }); 420 | Handlebars.registerHelper('formatIsoDate', function (date) { 421 | return new Handlebars.SafeString(typeof(date) !== 'undefined' ? new Date(date).iso() : ''); 422 | }); 423 | postHeaderTemplate = Handlebars.compile(data); 424 | }); 425 | 426 | // Kill the cache every 30 minutes. 427 | setInterval(emptyCache, cacheResetTimeInMillis); 428 | 429 | tweetLatestPost(); 430 | } 431 | 432 | // Gets the rendered HTML for this file, with header/footer. 433 | function generateHtmlForFile(file) { 434 | var fileData = generateHtmlAndMetadataForFile(file); 435 | return fileData.html(); 436 | } 437 | 438 | // Gets all the posts, paginated. 439 | // Goes through the posts, descending date order, and joins 440 | // days together until there are 10 or more posts. Once 10 441 | // posts are hit, that's considered a page. 442 | // Forcing to exactly 10 posts per page seemed artificial, and, 443 | // frankly, harder. 444 | function allPostsPaginated(completion) { 445 | allPostsSortedAndGrouped(function (postsByDay) { 446 | var pages = []; 447 | var thisPageDays = []; 448 | var count = 0; 449 | postsByDay.each(function (day) { 450 | count += day.articles.length; 451 | thisPageDays.push(day); 452 | // Reset count if need be 453 | if (count >= postsPerPage) { 454 | pages.push({ page: pages.length + 1, days: thisPageDays }); 455 | thisPageDays = []; 456 | count = 0; 457 | } 458 | }); 459 | 460 | if (thisPageDays.length > 0) { 461 | pages.push({ page: pages.length + 1, days: thisPageDays}); 462 | } 463 | 464 | completion(pages); 465 | }); 466 | } 467 | 468 | /*************************************************** 469 | * ROUTE HELPERS * 470 | ***************************************************/ 471 | 472 | function send404(response, file) { 473 | console.log('404: ' + file); 474 | response.status(404).send(generateHtmlForFile('posts/404.md')); 475 | } 476 | 477 | function loadAndSendMarkdownFile(file, response) { 478 | if (file.endsWith('.md')) { 479 | // Send the source file as requested. 480 | console.log('Sending source file: ' + file); 481 | fs.exists(file, function (exists) { 482 | if (exists) { 483 | fs.readFile(file, {encoding: 'UTF8'}, function (error, data) { 484 | if (error) { 485 | response.status(500).send({error: error}); 486 | return; 487 | } 488 | response.type('text/x-markdown; charset=UTF-8'); 489 | response.status(200).send(data); 490 | return; 491 | }); 492 | } else { 493 | response.status(400).send({error: 'Markdown file not found.'}); 494 | } 495 | }); 496 | } else if (fetchFromCache(file) !== null) { 497 | // Send the cached version. 498 | console.log('Sending cached file: ' + file); 499 | response.status(200).send(fetchFromCache(file).html()); 500 | } else { 501 | var found = false; 502 | // Is this a post? 503 | if (fs.existsSync(file + '.md')) { 504 | found = true; 505 | console.log('Sending file: ' + file); 506 | var html = generateHtmlForFile(file); 507 | response.status(200).send(html); 508 | // Or is this a redirect? 509 | } else if (fs.existsSync(file + '.redirect')) { 510 | var data = fs.readFileSync(file + '.redirect', {encoding: 'UTF8'}); 511 | if (data.length > 0) { 512 | var parts = data.split('\n'); 513 | if (parts.length >= 2) { 514 | found = true; 515 | console.log('Redirecting to: ' + parts[1]); 516 | response.redirect(parseInt(parts[0], 10), parts[1]); 517 | } 518 | } 519 | } 520 | 521 | if (!found) { 522 | send404(response, file); 523 | return; 524 | } 525 | } 526 | } 527 | 528 | // Sends a listing of an entire year's posts. 529 | function sendYearListing(request, response) { 530 | var year = request.params.slug; 531 | var retVal = '

' + year + '

'; 532 | var currentMonth = null; 533 | var anyFound = false; 534 | 535 | allPostsSortedAndGrouped(function (postsByDay) { 536 | postsByDay.each(function (day) { 537 | var thisDay = Date.create(day.date); 538 | if (thisDay.is(year)) { 539 | // Date.isBetween() is not inclusive, so back the from date up one 540 | var thisMonth = new Date(Number(year), Number(currentMonth)).addDays(-1); 541 | // ...and advance the to date by two (one to offset above, one to genuinely add). 542 | var nextMonth = Date.create(thisMonth).addMonths(1).addDays(2); 543 | 544 | //console.log(thisMonth.short() + ' <-- ' + thisDay.short() + ' --> ' + nextMonth.short() + '? ' + (thisDay.isBetween(thisMonth, nextMonth) ? 'YES' : 'NO')); 545 | if (currentMonth === null || !thisDay.isBetween(thisMonth, nextMonth)) { 546 | // If we've started a month list, end it, because we're on a new month now. 547 | if (currentMonth >= 0) { 548 | retVal += ''; 549 | } 550 | 551 | anyFound = true; 552 | currentMonth = thisDay.getMonth(); 553 | retVal += '

' + thisDay.format('{Month}') + '

\n
    '; 554 | } 555 | 556 | day.articles.each(function (article) { 557 | retVal += '
  • ' + article.metadata.Title + '
  • '; 558 | }); 559 | } 560 | }); 561 | 562 | if (!anyFound) { 563 | retVal += "No posts found."; 564 | } 565 | 566 | var updatedSource = performMetadataReplacements(siteMetadata, headerSource); 567 | var header = updatedSource.replace(metadataMarker + 'Title' + metadataMarker, 'Posts for ' + year); 568 | response.status(200).send(header + retVal + footerSource); 569 | }); 570 | 571 | } 572 | 573 | // Handles a route by trying the cache first. 574 | // file: file to try. 575 | // sender: function to send result to the client. Only parameter is an object that has the key 'body', which is raw HTML 576 | // generator: function to generate the raw HTML. Only parameter is a function that takes a completion handler that takes the raw HTML as its parameter. 577 | // baseRouteHandler() --> generator() to build HTML --> completion() to add to cache and send 578 | function baseRouteHandler(file, sender, generator) { 579 | if (fetchFromCache(file) === null) { 580 | console.log('Not in cache: ' + file); 581 | generator(function (postData) { 582 | addRenderedPostToCache(file, {body: postData}); 583 | sender({body: postData}); 584 | }); 585 | } else { 586 | console.log('In cache: ' + file); 587 | sender(fetchFromCache(file)); 588 | } 589 | } 590 | 591 | // Generates a RSS feed. 592 | // The linkGenerator is what determines if the articles will link 593 | // to this site or to the target of a link post; it takes an article. 594 | // The completion function takes an object: 595 | // { 596 | // date: // Date the generation happened 597 | // rss: // Rendered RSS 598 | // } 599 | function generateRss(request, feedUrl, linkGenerator, completion) { 600 | var feed = new Rss({ 601 | title: siteMetadata.SiteTitle, 602 | description: 'Posts to ' + siteMetadata.SiteTitle, 603 | feed_url: siteMetadata.SiteRoot + feedUrl, 604 | site_url: siteMetadata.SiteRoot, 605 | image_url: siteMetadata.SiteRoot + '/images/favicon.png', 606 | author: 'Your Name', 607 | copyright: '2013-' + new Date().getFullYear() + ' Your Name', 608 | language: 'en', 609 | pubDate: new Date().toString(), 610 | ttl: '60' 611 | }); 612 | 613 | var max = 10; 614 | var i = 0; 615 | allPostsSortedAndGrouped(function (postsByDay) { 616 | postsByDay.forEach(function (day) { 617 | day.articles.forEach(function (article) { 618 | if (i < max) { 619 | i += 1; 620 | feed.item({ 621 | title: article.metadata.Title, 622 | // Offset the time because Heroku's servers are GMT, whereas these dates are EST/EDT. 623 | date: new Date(article.metadata.Date).addHours(utcOffset), 624 | url: linkGenerator(article), 625 | guid: externalFilenameForFile(article.file, request), 626 | description: article.unwrappedBody.replace(//gm, "").concat(article.rssFooter) 627 | }); 628 | } 629 | }); 630 | }); 631 | 632 | completion({ 633 | date: new Date(), 634 | rss: feed.xml() 635 | }); 636 | }); 637 | } 638 | 639 | // Generates the HTML for the homepage 640 | function homepageBuilder(page, completion, redirect) { 641 | var indexInfo = generateHtmlAndMetadataForFile(postsRoot + 'index.md'); 642 | var footnoteIndex = 0; 643 | 644 | Handlebars.registerHelper('formatDate', function (date) { 645 | return new Handlebars.SafeString(new Date(date).format('{Weekday}
    {d}
    {Month}
    {yyyy}')); 646 | }); 647 | Handlebars.registerHelper('dateLink', function (date) { 648 | var parsedDate = new Date(date); 649 | return '/' + parsedDate.format("{yyyy}") + '/' + parsedDate.format("{M}") + '/' + parsedDate.format('{d}') + '/'; 650 | }); 651 | Handlebars.registerHelper('offsetFootnotes', function (html) { 652 | // Each day will call this helper once. We will offset the footnotes 653 | // to account for multiple days being on one page. This will avoid 654 | // conflicts with footnote numbers. If two days both have footnote, 655 | // they would both be "fn1". Which doesn't work; they need to be unique. 656 | var retVal = html.replace(footnoteAnchorRegex, '$&' + footnoteIndex); 657 | retVal = retVal.replace(footnoteIdRegex, '$&' + footnoteIndex); 658 | footnoteIndex += 1; 659 | 660 | return retVal; 661 | }); 662 | Handlebars.registerPartial('article', indexInfo.metadata.ArticlePartial); 663 | var dayTemplate = Handlebars.compile(indexInfo.metadata.DayTemplate); 664 | var footerTemplate = Handlebars.compile(indexInfo.metadata.FooterTemplate); 665 | 666 | var bodyHtml = ''; 667 | allPostsPaginated(function (pages) { 668 | // If we're asking for a page that doesn't exist, redirect. 669 | if (page < 0 || page > pages.length) { 670 | redirect(pages.length > 1 ? '/page/' + pages.length : '/'); 671 | return; 672 | } 673 | var days = pages[page - 1].days; 674 | days.forEach(function (day) { 675 | bodyHtml += dayTemplate(day); 676 | }); 677 | 678 | // If we have more data to display, set up footer links. 679 | var footerData = {}; 680 | if (page > 1) { 681 | footerData.prevPage = page - 1; 682 | } 683 | if (pages.length > page) { 684 | footerData.nextPage = page + 1; 685 | } 686 | 687 | var fileData = generateHtmlAndMetadataForFile(postsRoot + 'index.md'); 688 | var metadata = fileData.metadata; 689 | var header = fileData.header; 690 | // Replace ... with one-off for homepage, because it doesn't show both Page & Site titles. 691 | var titleBegin = header.indexOf('') + "<title>".length; 692 | var titleEnd = header.indexOf(''); 693 | header = header.substring(0, titleBegin) + metadata.SiteTitle + header.substring(titleEnd); 694 | // Carry on with body 695 | bodyHtml = performMetadataReplacements(metadata, bodyHtml); 696 | var fullHtml = header + bodyHtml + footerTemplate(footerData) + footerSource; 697 | completion(fullHtml); 698 | }); 699 | } 700 | 701 | /*************************************************** 702 | * ROUTES * 703 | ***************************************************/ 704 | 705 | app.get('/', function (request, response) { 706 | // Determine which page we're on, and make that the filename 707 | // so we cache by paginated page. 708 | var page = 1; 709 | if (typeof(request.query.p) !== 'undefined') { 710 | page = Number(request.query.p); 711 | if (isNaN(page)) { 712 | response.redirect('/'); 713 | return; 714 | } else { 715 | response.redirect('/page/' + page); 716 | return; 717 | } 718 | } 719 | 720 | // Do the standard route handler. Cough up a cached page if possible. 721 | baseRouteHandler('/page/1', function (cachedData) { 722 | response.status(200).send(cachedData.body); 723 | }, function (completion) { 724 | homepageBuilder(page, completion, function (destination) { 725 | response.redirect(destination); 726 | }); 727 | }); 728 | }); 729 | 730 | app.get('/page/:page', function (request, response) { 731 | var page = Number(request.params.page); 732 | if (isNaN(page)) { 733 | response.redirect('/'); 734 | return; 735 | } 736 | 737 | // Do the standard route handler. Cough up a cached page if possible. 738 | baseRouteHandler('/page/' + page, function (cachedData) { 739 | response.status(200).send(cachedData.body); 740 | }, function (completion) { 741 | homepageBuilder(page, completion, function (destination) { 742 | response.redirect(destination); 743 | }); 744 | }); 745 | }); 746 | 747 | app.get('/rss', function (request, response) { 748 | if ('user-agent' in request.headers && request.headers['user-agent'].has('subscriber')) { 749 | console.log('RSS: ' + request.headers['user-agent']); 750 | } 751 | response.type('application/rss+xml'); 752 | 753 | var previouslyRendered = renderedRss[request.hostname]; 754 | if (typeof(previouslyRendered) === 'undefined' || 755 | typeof(previouslyRendered.date) === 'undefined' || 756 | new Date().getTime() - previouslyRendered.date.getTime() > 3600000) 757 | { 758 | generateRss(request, '/rss', function (article) { 759 | if (typeof(article.metadata.Link) !== 'undefined') { 760 | return article.metadata.Link; 761 | } 762 | return externalFilenameForFile(article.file, request); 763 | }, function (rssPair) { 764 | renderedRss[request.hostname] = rssPair; 765 | response.status(200).send(rssPair.rss); 766 | }); 767 | } else { 768 | response.status(200).send(previouslyRendered.rss); 769 | } 770 | }); 771 | 772 | app.get('/rss-alternate', function (request, response) { 773 | if ('user-agent' in request.headers && request.headers['user-agent'].has('subscriber')) { 774 | console.log('Alternate RSS: ' + request.headers['user-agent']); 775 | } 776 | response.type('application/rss+xml'); 777 | 778 | var previouslyRendered = renderedRss[request.hostname]; 779 | if (typeof(previouslyRendered) === 'undefined' || 780 | typeof(previouslyRendered.date) === 'undefined' || 781 | new Date().getTime() - previouslyRendered.date.getTime() > 3600000) 782 | { 783 | generateRss(request, '/rss-alternate', function (article) { 784 | return externalFilenameForFile(article.file, request); 785 | }, function (rssPair) { 786 | renderedAlternateRss[request.hostname] = rssPair; 787 | response.status(200).send(rssPair.rss); 788 | }); 789 | } else { 790 | response.status(200).send(previouslyRendered.rss); 791 | } 792 | }); 793 | 794 | // Month view 795 | app.get('/:year/:month', function (request, response) { 796 | 797 | allPostsSortedAndGrouped(function (postsByDay) { 798 | var seekingDay = new Date(request.params.year, request.params.month - 1); 799 | 800 | var html = '

    ' + seekingDay.format('{Month} {yyyy}') + "

    "; 801 | var anyFound = false; 802 | postsByDay.each(function (day) { 803 | var thisDay = new Date(day.date); 804 | if (thisDay.is(seekingDay.format('{Month} {yyyy}'))) { 805 | anyFound = true; 806 | 807 | html += "

    " + thisDay.format('{Weekday}, {Month} {d}') + "

    '; 812 | } 813 | }); 814 | 815 | if (!anyFound) { 816 | html += "No posts found."; 817 | } 818 | var header = performMetadataReplacements(siteMetadata, headerSource).replace( 819 | metadataMarker + 'Title' + metadataMarker, 820 | seekingDay.format('{Month} {yyyy}') + '—' + siteMetadata.SiteTitle); 821 | response.status(200).send(header + html + footerSource); 822 | }); 823 | }); 824 | 825 | // Day view 826 | app.get('/:year/:month/:day', function (request, response) { 827 | 828 | allPostsSortedAndGrouped(function (postsByDay) { 829 | var seekingDay = new Date(request.params.year, request.params.month - 1, request.params.day); 830 | 831 | postsByDay.each(function (day) { 832 | var thisDay = new Date(day.date); 833 | if (thisDay.is(seekingDay)) { 834 | var html = "

    Posts from " + seekingDay.format('{Weekday}, {Month} {d}, {yyyy}') + "

      "; 835 | day.articles.each(function (article) { 836 | html += '
    • ' + article.metadata.Title + '
    • '; 837 | }); 838 | 839 | var header = performMetadataReplacements(siteMetadata, headerSource).replace( 840 | metadataMarker + 'Title' + metadataMarker, 841 | seekingDay.format('{Weekday}, {Month} {d}, {Year}')); 842 | response.status(200).send(header + html + footerSource); 843 | } 844 | }); 845 | }); 846 | }); 847 | 848 | 849 | // Get a blog post, such as /2014/3/17/birthday 850 | app.get('/:year/:month/:day/:slug', function (request, response) { 851 | var file = postsRoot + request.params.year + '/' + request.params.month + '/' + request.params.day + '/' + request.params.slug; 852 | 853 | loadAndSendMarkdownFile(file, response); 854 | }); 855 | 856 | // Empties the cache. 857 | // app.get('/tosscache', function (request, response) { 858 | // emptyCache(); 859 | // response.send(205); 860 | // }); 861 | 862 | // Show some basic stats 863 | app.get('/count', function (request, response) { 864 | console.log("/count"); 865 | allPostsSortedAndGrouped(function (all) { 866 | var count = 0; 867 | var day; 868 | var days = 0; 869 | for (day in _.keys(all)) { 870 | days += 1; 871 | count += all[day].articles.length; 872 | } 873 | 874 | response.send(count + ' articles, across ' + days + ' days that have at least one post.'); 875 | }); 876 | }); 877 | 878 | 879 | 880 | app.post('/render-draft', [requireAuth, bodyParser.urlencoded({extended: true})], function (request, response) { 881 | var pieces = getLinesFromData(request.body.markdown); 882 | pieces.metadata = _.union(pieces.metadata, ["@@ BodyClass=post"]); 883 | //var titleIndex = pieces.metadata.findIndex(/^@@ Title=/); 884 | //pieces.metadata[titleIndex] = "@@ Title=DRAFT – " + pieces.metadata[titleIndex].substr(9) + " – DRAFT"; 885 | var result = generateHtmlAndMetadataForLines(pieces); 886 | response.send(result.html()); 887 | }); 888 | 889 | // Support for non-blog posts, such as /about, as well as years, such as /2014. 890 | app.get('/:slug', function (request, response) { 891 | // If this is a typical slug, send the file 892 | if (isNaN(request.params.slug)) { 893 | var file = postsRoot + request.params.slug; 894 | loadAndSendMarkdownFile(file, response); 895 | // If it's a year, handle that. 896 | } else if (request.params.slug >= 2000) { 897 | sendYearListing(request, response); 898 | // If it's garbage (ie, a year less than 2013), send a 404. 899 | } else { 900 | send404(response, request.params.slug); 901 | } 902 | }); 903 | 904 | /*************************************************** 905 | * STARTUP * 906 | ***************************************************/ 907 | init(); 908 | var port = Number(process.env.PORT || 5000); 909 | server.listen(port, function () { 910 | console.log('Camel v' + version + ' server started on port %s', server.address().port); 911 | }); 912 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": [ 3 | "./", 4 | "public/css/", 5 | "public/images/", 6 | "posts/" 7 | ], 8 | "ext": "js md jpg png css" 9 | } 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Camel", 3 | "version": "1.5.6", 4 | "description": "FeatureLiss blogging software", 5 | "keywords": [ 6 | "blog", 7 | "blogging", 8 | "camel" 9 | ], 10 | "main": "camel.js", 11 | "homepage": "http://github.com/cliss/camel/", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/cliss/camel.git" 15 | }, 16 | "author": { 17 | "name": "Casey Liss", 18 | "url": "http://www.caseyliss.com/" 19 | }, 20 | "contributors": [ 21 | { 22 | "name": "Max Bucknell", 23 | "url": "http://maxbucknell.com/" 24 | }, 25 | { 26 | "name": "Ben Elsen", 27 | "url": "http://benelsen.com/" 28 | }, 29 | { 30 | "name": "Benjamin Esham", 31 | "url": "http://esham.io/" 32 | }, 33 | { 34 | "name": "Sergei Filippov", 35 | "url": "http://haiku.co.nz/" 36 | }, 37 | { 38 | "name": "ksgant", 39 | "url": "https://github.com/ksgant/" 40 | }, 41 | { 42 | "name": "Robbie Mckennie", 43 | "url": "http://herebedragons.no-ip.org/" 44 | }, 45 | { 46 | "name": "Marco Vega", 47 | "url": "http://www.extd.co/" 48 | } 49 | ], 50 | "bugs": "https://github.com/cliss/camel/issues", 51 | "scripts": { 52 | "start": "nodemon ./camel.js", 53 | "test": "echo \"Error: no test specified\" && exit 1" 54 | }, 55 | "license": "MIT", 56 | "dependencies": { 57 | "basic-auth": "^1.0.4", 58 | "body-parser": "^1.15.1", 59 | "compression": "~1.6.2", 60 | "dotenv": "^2.0.0", 61 | "express": "^4.13.4", 62 | "handlebars": "^4.0.5", 63 | "markdown-it": "^13.0.1", 64 | "markdown-it-footnote": "~2.0.0", 65 | "promise": "^7.0.4", 66 | "q-io": "^1.13.2", 67 | "rss": "~1.2.1", 68 | "sugar": "~1.4.1", 69 | "twitter": "~1.3.0", 70 | "underscore": "^1.13.3" 71 | }, 72 | "engines": { 73 | "node": "0.12.x" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /posts/2014/5/1/sample-post.md: -------------------------------------------------------------------------------- 1 | @@ Title=Test Post 2 | @@ Date=2014-05 17:50 3 | @@ Description=This is a short description used in Twitter cards and Facebook Open Graph. 4 | @@ Image=http://somehost.com/someimage.png 5 | 6 | This is a *test post* entitled "@@Title@@". 7 | -------------------------------------------------------------------------------- /posts/2015/2/16/some-awesome-website.redirect: -------------------------------------------------------------------------------- 1 | 302 2 | http://www.caseyliss.com/ 3 | -------------------------------------------------------------------------------- /posts/2015/2/6/sample-link-post.md: -------------------------------------------------------------------------------- 1 | @@ Title=Sample Link Post 2 | @@ Date=2015-02-06 12:00 3 | @@ Link=http://www.vt.edu/ 4 | 5 | This is a sample *link* post. It links to `@@Link@@`. 6 | -------------------------------------------------------------------------------- /posts/404.md: -------------------------------------------------------------------------------- 1 | @@ Title=Not Found! 2 | @@ HideHeader=true 3 | 4 | Not found. 5 | -------------------------------------------------------------------------------- /posts/about.md: -------------------------------------------------------------------------------- 1 | @@ Title=About Page 2 | @@ Date=2014-05-01 18:08 3 | 4 | This is a sample about page, that can be accessed via `/about`. 5 | -------------------------------------------------------------------------------- /posts/index.md: -------------------------------------------------------------------------------- 1 | @@ Title=Home 2 | @@ BodyClass=homepage 3 | @@ DayTemplate=
      {{#each articles}}{{> article}}{{/each}}

      4 | @@ ArticlePartial=
      {{{postHeader}}}{{{offsetFootnotes unwrappedBody}}}
      5 | @@ FooterTemplate=
      {{#if prevPage}}« Newer{{/if}}{{#if nextPage}}» Older{{/if}}
      6 | -------------------------------------------------------------------------------- /public/css/site.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cliss/camel/9cdd8289d74b7156f807e3051caf51e7960fe174/public/css/site.css -------------------------------------------------------------------------------- /templates/defaultTags.html: -------------------------------------------------------------------------------- 1 | @@ SiteTitle=Sample Site 2 | @@ SiteRoot=http://localhost:5000 3 | @@ Description=Read more on Sample Site 4 | @@ Image= 5 | -------------------------------------------------------------------------------- /templates/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /templates/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | @@SiteTitle@@ — @@Title@@ 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /templates/postHeader.html: -------------------------------------------------------------------------------- 1 | {{#if Link}} 2 | {{Title}}
      3 | Permalink 4 | {{else}} 5 | {{Title}} 6 | {{/if}} 7 | -------------------------------------------------------------------------------- /templates/rssFooter.html: -------------------------------------------------------------------------------- 1 | {{#if Link}} 2 |

      Read on @@SiteTitle@@

      3 | {{/if}} 4 | -------------------------------------------------------------------------------- /typings/body-parser/body-parser.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for body-parser 2 | // Project: http://expressjs.com 3 | // Definitions by: Santi Albo , VILIC VANE , Jonathan Häberle 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare module "body-parser" { 9 | import * as express from "express"; 10 | 11 | /** 12 | * bodyParser: use individual json/urlencoded middlewares 13 | * @deprecated 14 | */ 15 | 16 | function bodyParser(options?: { 17 | /** 18 | * if deflated bodies will be inflated. (default: true) 19 | */ 20 | inflate?: boolean; 21 | /** 22 | * maximum request body size. (default: '100kb') 23 | */ 24 | limit?: any; 25 | /** 26 | * function to verify body content, the parsing can be aborted by throwing an error. 27 | */ 28 | verify?: (req: express.Request, res: express.Response, buf: Buffer, encoding: string) => void; 29 | /** 30 | * only parse objects and arrays. (default: true) 31 | */ 32 | strict?: boolean; 33 | /** 34 | * passed to JSON.parse(). 35 | */ 36 | receiver?: (key: string, value: any) => any; 37 | /** 38 | * parse extended syntax with the qs module. (default: true) 39 | */ 40 | extended?: boolean; 41 | }): express.RequestHandler; 42 | 43 | module bodyParser { 44 | export function json(options?: { 45 | /** 46 | * if deflated bodies will be inflated. (default: true) 47 | */ 48 | inflate?: boolean; 49 | /** 50 | * maximum request body size. (default: '100kb') 51 | */ 52 | limit?: any; 53 | /** 54 | * request content-type to parse, passed directly to the type-is library. (default: 'json') 55 | */ 56 | type?: any; 57 | /** 58 | * function to verify body content, the parsing can be aborted by throwing an error. 59 | */ 60 | verify?: (req: express.Request, res: express.Response, buf: Buffer, encoding: string) => void; 61 | /** 62 | * only parse objects and arrays. (default: true) 63 | */ 64 | strict?: boolean; 65 | /** 66 | * passed to JSON.parse(). 67 | */ 68 | receiver?: (key: string, value: any) => any; 69 | }): express.RequestHandler; 70 | 71 | export function raw(options?: { 72 | /** 73 | * if deflated bodies will be inflated. (default: true) 74 | */ 75 | inflate?: boolean; 76 | /** 77 | * maximum request body size. (default: '100kb') 78 | */ 79 | limit?: any; 80 | /** 81 | * request content-type to parse, passed directly to the type-is library. (default: 'application/octet-stream') 82 | */ 83 | type?: any; 84 | /** 85 | * function to verify body content, the parsing can be aborted by throwing an error. 86 | */ 87 | verify?: (req: express.Request, res: express.Response, buf: Buffer, encoding: string) => void; 88 | }): express.RequestHandler; 89 | 90 | export function text(options?: { 91 | /** 92 | * if deflated bodies will be inflated. (default: true) 93 | */ 94 | inflate?: boolean; 95 | /** 96 | * maximum request body size. (default: '100kb') 97 | */ 98 | limit?: any; 99 | /** 100 | * request content-type to parse, passed directly to the type-is library. (default: 'text/plain') 101 | */ 102 | type?: any; 103 | /** 104 | * function to verify body content, the parsing can be aborted by throwing an error. 105 | */ 106 | verify?: (req: express.Request, res: express.Response, buf: Buffer, encoding: string) => void; 107 | /** 108 | * the default charset to parse as, if not specified in content-type. (default: 'utf-8') 109 | */ 110 | defaultCharset?: string; 111 | }): express.RequestHandler; 112 | 113 | export function urlencoded(options?: { 114 | /** 115 | * if deflated bodies will be inflated. (default: true) 116 | */ 117 | inflate?: boolean; 118 | /** 119 | * maximum request body size. (default: '100kb') 120 | */ 121 | limit?: any; 122 | /** 123 | * request content-type to parse, passed directly to the type-is library. (default: 'urlencoded') 124 | */ 125 | type?: any; 126 | /** 127 | * function to verify body content, the parsing can be aborted by throwing an error. 128 | */ 129 | verify?: (req: express.Request, res: express.Response, buf: Buffer, encoding: string) => void; 130 | /** 131 | * parse extended syntax with the qs module. (default: true) 132 | */ 133 | extended?: boolean; 134 | }): express.RequestHandler; 135 | } 136 | 137 | export = bodyParser; 138 | } -------------------------------------------------------------------------------- /typings/express/express.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Express 4.x 2 | // Project: http://expressjs.com 3 | // Definitions by: Boris Yankov 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /* =================== USAGE =================== 7 | 8 | import express = require('express'); 9 | var app = express(); 10 | 11 | =============================================== */ 12 | 13 | /// 14 | 15 | declare module Express { 16 | 17 | // These open interfaces may be extended in an application-specific manner via declaration merging. 18 | // See for example method-override.d.ts (https://github.com/borisyankov/DefinitelyTyped/blob/master/method-override/method-override.d.ts) 19 | export interface Request { } 20 | export interface Response { } 21 | export interface Application { } 22 | } 23 | 24 | 25 | declare module "express" { 26 | import http = require('http'); 27 | 28 | function e(): e.Express; 29 | 30 | module e { 31 | interface IRoute { 32 | path: string; 33 | stack: any; 34 | all(...handler: RequestHandler[]): IRoute; 35 | get(...handler: RequestHandler[]): IRoute; 36 | post(...handler: RequestHandler[]): IRoute; 37 | put(...handler: RequestHandler[]): IRoute; 38 | delete(...handler: RequestHandler[]): IRoute; 39 | patch(...handler: RequestHandler[]): IRoute; 40 | options(...handler: RequestHandler[]): IRoute; 41 | } 42 | 43 | interface IRouterMatcher { 44 | (name: string, ...handlers: RequestHandler[]): T; 45 | (name: RegExp, ...handlers: RequestHandler[]): T; 46 | } 47 | 48 | interface IRouter extends RequestHandler { 49 | /** 50 | * Map the given param placeholder `name`(s) to the given callback(s). 51 | * 52 | * Parameter mapping is used to provide pre-conditions to routes 53 | * which use normalized placeholders. For example a _:user_id_ parameter 54 | * could automatically load a user's information from the database without 55 | * any additional code, 56 | * 57 | * The callback uses the samesignature as middleware, the only differencing 58 | * being that the value of the placeholder is passed, in this case the _id_ 59 | * of the user. Once the `next()` function is invoked, just like middleware 60 | * it will continue on to execute the route, or subsequent parameter functions. 61 | * 62 | * app.param('user_id', function(req, res, next, id){ 63 | * User.find(id, function(err, user){ 64 | * if (err) { 65 | * next(err); 66 | * } else if (user) { 67 | * req.user = user; 68 | * next(); 69 | * } else { 70 | * next(new Error('failed to load user')); 71 | * } 72 | * }); 73 | * }); 74 | * 75 | * @param name 76 | * @param fn 77 | */ 78 | param(name: string, handler: RequestParamHandler): T; 79 | param(name: string, matcher: RegExp): T; 80 | param(name: string, mapper: (param: any) => any): T; 81 | // Alternatively, you can pass only a callback, in which case you have the opportunity to alter the app.param() API 82 | param(callback: (name: string, matcher: RegExp) => RequestParamHandler): T; 83 | 84 | /** 85 | * Special-cased "all" method, applying the given route `path`, 86 | * middleware, and callback to _every_ HTTP method. 87 | * 88 | * @param path 89 | * @param fn 90 | */ 91 | all: IRouterMatcher; 92 | get: IRouterMatcher; 93 | post: IRouterMatcher; 94 | put: IRouterMatcher; 95 | delete: IRouterMatcher; 96 | patch: IRouterMatcher; 97 | options: IRouterMatcher; 98 | 99 | route(path: string): IRoute; 100 | 101 | use(...handler: RequestHandler[]): T; 102 | use(handler: ErrorRequestHandler): T; 103 | use(path: string, ...handler: RequestHandler[]): T; 104 | use(path: string, handler: ErrorRequestHandler): T; 105 | } 106 | 107 | export function Router(options?: any): Router; 108 | 109 | export interface Router extends IRouter {} 110 | 111 | interface CookieOptions { 112 | maxAge?: number; 113 | signed?: boolean; 114 | expires?: Date; 115 | httpOnly?: boolean; 116 | path?: string; 117 | domain?: string; 118 | secure?: boolean; 119 | } 120 | 121 | interface Errback { (err: Error): void; } 122 | 123 | interface Request extends http.ServerRequest, Express.Request { 124 | 125 | /** 126 | * Return request header. 127 | * 128 | * The `Referrer` header field is special-cased, 129 | * both `Referrer` and `Referer` are interchangeable. 130 | * 131 | * Examples: 132 | * 133 | * req.get('Content-Type'); 134 | * // => "text/plain" 135 | * 136 | * req.get('content-type'); 137 | * // => "text/plain" 138 | * 139 | * req.get('Something'); 140 | * // => undefined 141 | * 142 | * Aliased as `req.header()`. 143 | * 144 | * @param name 145 | */ 146 | get (name: string): string; 147 | 148 | header(name: string): string; 149 | 150 | headers: { [key: string]: string; }; 151 | 152 | /** 153 | * Check if the given `type(s)` is acceptable, returning 154 | * the best match when true, otherwise `undefined`, in which 155 | * case you should respond with 406 "Not Acceptable". 156 | * 157 | * The `type` value may be a single mime type string 158 | * such as "application/json", the extension name 159 | * such as "json", a comma-delimted list such as "json, html, text/plain", 160 | * or an array `["json", "html", "text/plain"]`. When a list 161 | * or array is given the _best_ match, if any is returned. 162 | * 163 | * Examples: 164 | * 165 | * // Accept: text/html 166 | * req.accepts('html'); 167 | * // => "html" 168 | * 169 | * // Accept: text/*, application/json 170 | * req.accepts('html'); 171 | * // => "html" 172 | * req.accepts('text/html'); 173 | * // => "text/html" 174 | * req.accepts('json, text'); 175 | * // => "json" 176 | * req.accepts('application/json'); 177 | * // => "application/json" 178 | * 179 | * // Accept: text/*, application/json 180 | * req.accepts('image/png'); 181 | * req.accepts('png'); 182 | * // => undefined 183 | * 184 | * // Accept: text/*;q=.5, application/json 185 | * req.accepts(['html', 'json']); 186 | * req.accepts('html, json'); 187 | * // => "json" 188 | */ 189 | accepts(type: string): string; 190 | 191 | accepts(type: string[]): string; 192 | 193 | /** 194 | * Check if the given `charset` is acceptable, 195 | * otherwise you should respond with 406 "Not Acceptable". 196 | * 197 | * @param charset 198 | */ 199 | acceptsCharset(charset: string): boolean; 200 | 201 | /** 202 | * Check if the given `lang` is acceptable, 203 | * otherwise you should respond with 406 "Not Acceptable". 204 | * 205 | * @param lang 206 | */ 207 | acceptsLanguage(lang: string): boolean; 208 | 209 | /** 210 | * Parse Range header field, 211 | * capping to the given `size`. 212 | * 213 | * Unspecified ranges such as "0-" require 214 | * knowledge of your resource length. In 215 | * the case of a byte range this is of course 216 | * the total number of bytes. If the Range 217 | * header field is not given `null` is returned, 218 | * `-1` when unsatisfiable, `-2` when syntactically invalid. 219 | * 220 | * NOTE: remember that ranges are inclusive, so 221 | * for example "Range: users=0-3" should respond 222 | * with 4 users when available, not 3. 223 | * 224 | * @param size 225 | */ 226 | range(size: number): any[]; 227 | 228 | /** 229 | * Return an array of Accepted media types 230 | * ordered from highest quality to lowest. 231 | */ 232 | accepted: MediaType[]; 233 | 234 | /** 235 | * Return an array of Accepted languages 236 | * ordered from highest quality to lowest. 237 | * 238 | * Examples: 239 | * 240 | * Accept-Language: en;q=.5, en-us 241 | * ['en-us', 'en'] 242 | */ 243 | acceptedLanguages: any[]; 244 | 245 | /** 246 | * Return an array of Accepted charsets 247 | * ordered from highest quality to lowest. 248 | * 249 | * Examples: 250 | * 251 | * Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8 252 | * ['unicode-1-1', 'iso-8859-5'] 253 | */ 254 | acceptedCharsets: any[]; 255 | 256 | /** 257 | * Return the value of param `name` when present or `defaultValue`. 258 | * 259 | * - Checks route placeholders, ex: _/user/:id_ 260 | * - Checks body params, ex: id=12, {"id":12} 261 | * - Checks query string params, ex: ?id=12 262 | * 263 | * To utilize request bodies, `req.body` 264 | * should be an object. This can be done by using 265 | * the `connect.bodyParser()` middleware. 266 | * 267 | * @param name 268 | * @param defaultValue 269 | */ 270 | param(name: string, defaultValue?: any): string; 271 | 272 | /** 273 | * Check if the incoming request contains the "Content-Type" 274 | * header field, and it contains the give mime `type`. 275 | * 276 | * Examples: 277 | * 278 | * // With Content-Type: text/html; charset=utf-8 279 | * req.is('html'); 280 | * req.is('text/html'); 281 | * req.is('text/*'); 282 | * // => true 283 | * 284 | * // When Content-Type is application/json 285 | * req.is('json'); 286 | * req.is('application/json'); 287 | * req.is('application/*'); 288 | * // => true 289 | * 290 | * req.is('html'); 291 | * // => false 292 | * 293 | * @param type 294 | */ 295 | is(type: string): boolean; 296 | 297 | /** 298 | * Return the protocol string "http" or "https" 299 | * when requested with TLS. When the "trust proxy" 300 | * setting is enabled the "X-Forwarded-Proto" header 301 | * field will be trusted. If you're running behind 302 | * a reverse proxy that supplies https for you this 303 | * may be enabled. 304 | */ 305 | protocol: string; 306 | 307 | /** 308 | * Short-hand for: 309 | * 310 | * req.protocol == 'https' 311 | */ 312 | secure: boolean; 313 | 314 | /** 315 | * Return the remote address, or when 316 | * "trust proxy" is `true` return 317 | * the upstream addr. 318 | */ 319 | ip: string; 320 | 321 | /** 322 | * When "trust proxy" is `true`, parse 323 | * the "X-Forwarded-For" ip address list. 324 | * 325 | * For example if the value were "client, proxy1, proxy2" 326 | * you would receive the array `["client", "proxy1", "proxy2"]` 327 | * where "proxy2" is the furthest down-stream. 328 | */ 329 | ips: string[]; 330 | 331 | /** 332 | * Return subdomains as an array. 333 | * 334 | * Subdomains are the dot-separated parts of the host before the main domain of 335 | * the app. By default, the domain of the app is assumed to be the last two 336 | * parts of the host. This can be changed by setting "subdomain offset". 337 | * 338 | * For example, if the domain is "tobi.ferrets.example.com": 339 | * If "subdomain offset" is not set, req.subdomains is `["ferrets", "tobi"]`. 340 | * If "subdomain offset" is 3, req.subdomains is `["tobi"]`. 341 | */ 342 | subdomains: string[]; 343 | 344 | /** 345 | * Short-hand for `url.parse(req.url).pathname`. 346 | */ 347 | path: string; 348 | 349 | /** 350 | * Parse the "Host" header field hostname. 351 | */ 352 | host: string; 353 | 354 | /** 355 | * Check if the request is fresh, aka 356 | * Last-Modified and/or the ETag 357 | * still match. 358 | */ 359 | fresh: boolean; 360 | 361 | /** 362 | * Check if the request is stale, aka 363 | * "Last-Modified" and / or the "ETag" for the 364 | * resource has changed. 365 | */ 366 | stale: boolean; 367 | 368 | /** 369 | * Check if the request was an _XMLHttpRequest_. 370 | */ 371 | xhr: boolean; 372 | 373 | //body: { username: string; password: string; remember: boolean; title: string; }; 374 | body: any; 375 | 376 | //cookies: { string; remember: boolean; }; 377 | cookies: any; 378 | 379 | method: string; 380 | 381 | params: any; 382 | 383 | user: any; 384 | 385 | authenticatedUser: any; 386 | 387 | files: any; 388 | 389 | /** 390 | * Clear cookie `name`. 391 | * 392 | * @param name 393 | * @param options 394 | */ 395 | clearCookie(name: string, options?: any): Response; 396 | 397 | query: any; 398 | 399 | route: any; 400 | 401 | signedCookies: any; 402 | 403 | originalUrl: string; 404 | 405 | url: string; 406 | } 407 | 408 | interface MediaType { 409 | value: string; 410 | quality: number; 411 | type: string; 412 | subtype: string; 413 | } 414 | 415 | interface Send { 416 | (status: number, body?: any): Response; 417 | (body: any): Response; 418 | } 419 | 420 | interface Response extends http.ServerResponse, Express.Response { 421 | /** 422 | * Set status `code`. 423 | * 424 | * @param code 425 | */ 426 | status(code: number): Response; 427 | 428 | /** 429 | * Set the response HTTP status code to `statusCode` and send its string representation as the response body. 430 | * @link http://expressjs.com/4x/api.html#res.sendStatus 431 | * 432 | * Examples: 433 | * 434 | * res.sendStatus(200); // equivalent to res.status(200).send('OK') 435 | * res.sendStatus(403); // equivalent to res.status(403).send('Forbidden') 436 | * res.sendStatus(404); // equivalent to res.status(404).send('Not Found') 437 | * res.sendStatus(500); // equivalent to res.status(500).send('Internal Server Error') 438 | * 439 | * @param code 440 | */ 441 | sendStatus(code: number): Response; 442 | 443 | /** 444 | * Set Link header field with the given `links`. 445 | * 446 | * Examples: 447 | * 448 | * res.links({ 449 | * next: 'http://api.example.com/users?page=2', 450 | * last: 'http://api.example.com/users?page=5' 451 | * }); 452 | * 453 | * @param links 454 | */ 455 | links(links: any): Response; 456 | 457 | /** 458 | * Send a response. 459 | * 460 | * Examples: 461 | * 462 | * res.send(new Buffer('wahoo')); 463 | * res.send({ some: 'json' }); 464 | * res.send('

      some html

      '); 465 | * res.send(404, 'Sorry, cant find that'); 466 | * res.send(404); 467 | */ 468 | send: Send; 469 | 470 | /** 471 | * Send JSON response. 472 | * 473 | * Examples: 474 | * 475 | * res.json(null); 476 | * res.json({ user: 'tj' }); 477 | * res.json(500, 'oh noes!'); 478 | * res.json(404, 'I dont have that'); 479 | */ 480 | json: Send; 481 | 482 | /** 483 | * Send JSON response with JSONP callback support. 484 | * 485 | * Examples: 486 | * 487 | * res.jsonp(null); 488 | * res.jsonp({ user: 'tj' }); 489 | * res.jsonp(500, 'oh noes!'); 490 | * res.jsonp(404, 'I dont have that'); 491 | */ 492 | jsonp: Send; 493 | 494 | /** 495 | * Transfer the file at the given `path`. 496 | * 497 | * Automatically sets the _Content-Type_ response header field. 498 | * The callback `fn(err)` is invoked when the transfer is complete 499 | * or when an error occurs. Be sure to check `res.sentHeader` 500 | * if you wish to attempt responding, as the header and some data 501 | * may have already been transferred. 502 | * 503 | * Options: 504 | * 505 | * - `maxAge` defaulting to 0 (can be string converted by `ms`) 506 | * - `root` root directory for relative filenames 507 | * - `headers` object of headers to serve with file 508 | * - `dotfiles` serve dotfiles, defaulting to false; can be `"allow"` to send them 509 | * 510 | * Other options are passed along to `send`. 511 | * 512 | * Examples: 513 | * 514 | * The following example illustrates how `res.sendFile()` may 515 | * be used as an alternative for the `static()` middleware for 516 | * dynamic situations. The code backing `res.sendFile()` is actually 517 | * the same code, so HTTP cache support etc is identical. 518 | * 519 | * app.get('/user/:uid/photos/:file', function(req, res){ 520 | * var uid = req.params.uid 521 | * , file = req.params.file; 522 | * 523 | * req.user.mayViewFilesFrom(uid, function(yes){ 524 | * if (yes) { 525 | * res.sendFile('/uploads/' + uid + '/' + file); 526 | * } else { 527 | * res.send(403, 'Sorry! you cant see that.'); 528 | * } 529 | * }); 530 | * }); 531 | * 532 | * @api public 533 | */ 534 | sendFile(path: string): void; 535 | sendFile(path: string, options: any): void; 536 | sendFile(path: string, fn: Errback): void; 537 | sendFile(path: string, options: any, fn: Errback): void; 538 | 539 | /** 540 | * @deprecated Use sendFile instead. 541 | */ 542 | sendfile(path: string): void; 543 | /** 544 | * @deprecated Use sendFile instead. 545 | */ 546 | sendfile(path: string, options: any): void; 547 | /** 548 | * @deprecated Use sendFile instead. 549 | */ 550 | sendfile(path: string, fn: Errback): void; 551 | /** 552 | * @deprecated Use sendFile instead. 553 | */ 554 | sendfile(path: string, options: any, fn: Errback): void; 555 | 556 | /** 557 | * Transfer the file at the given `path` as an attachment. 558 | * 559 | * Optionally providing an alternate attachment `filename`, 560 | * and optional callback `fn(err)`. The callback is invoked 561 | * when the data transfer is complete, or when an error has 562 | * ocurred. Be sure to check `res.headerSent` if you plan to respond. 563 | * 564 | * This method uses `res.sendfile()`. 565 | */ 566 | download(path: string): void; 567 | download(path: string, filename: string): void; 568 | download(path: string, fn: Errback): void; 569 | download(path: string, filename: string, fn: Errback): void; 570 | 571 | /** 572 | * Set _Content-Type_ response header with `type` through `mime.lookup()` 573 | * when it does not contain "/", or set the Content-Type to `type` otherwise. 574 | * 575 | * Examples: 576 | * 577 | * res.type('.html'); 578 | * res.type('html'); 579 | * res.type('json'); 580 | * res.type('application/json'); 581 | * res.type('png'); 582 | * 583 | * @param type 584 | */ 585 | contentType(type: string): Response; 586 | 587 | /** 588 | * Set _Content-Type_ response header with `type` through `mime.lookup()` 589 | * when it does not contain "/", or set the Content-Type to `type` otherwise. 590 | * 591 | * Examples: 592 | * 593 | * res.type('.html'); 594 | * res.type('html'); 595 | * res.type('json'); 596 | * res.type('application/json'); 597 | * res.type('png'); 598 | * 599 | * @param type 600 | */ 601 | type(type: string): Response; 602 | 603 | /** 604 | * Respond to the Acceptable formats using an `obj` 605 | * of mime-type callbacks. 606 | * 607 | * This method uses `req.accepted`, an array of 608 | * acceptable types ordered by their quality values. 609 | * When "Accept" is not present the _first_ callback 610 | * is invoked, otherwise the first match is used. When 611 | * no match is performed the server responds with 612 | * 406 "Not Acceptable". 613 | * 614 | * Content-Type is set for you, however if you choose 615 | * you may alter this within the callback using `res.type()` 616 | * or `res.set('Content-Type', ...)`. 617 | * 618 | * res.format({ 619 | * 'text/plain': function(){ 620 | * res.send('hey'); 621 | * }, 622 | * 623 | * 'text/html': function(){ 624 | * res.send('

      hey

      '); 625 | * }, 626 | * 627 | * 'appliation/json': function(){ 628 | * res.send({ message: 'hey' }); 629 | * } 630 | * }); 631 | * 632 | * In addition to canonicalized MIME types you may 633 | * also use extnames mapped to these types: 634 | * 635 | * res.format({ 636 | * text: function(){ 637 | * res.send('hey'); 638 | * }, 639 | * 640 | * html: function(){ 641 | * res.send('

      hey

      '); 642 | * }, 643 | * 644 | * json: function(){ 645 | * res.send({ message: 'hey' }); 646 | * } 647 | * }); 648 | * 649 | * By default Express passes an `Error` 650 | * with a `.status` of 406 to `next(err)` 651 | * if a match is not made. If you provide 652 | * a `.default` callback it will be invoked 653 | * instead. 654 | * 655 | * @param obj 656 | */ 657 | format(obj: any): Response; 658 | 659 | /** 660 | * Set _Content-Disposition_ header to _attachment_ with optional `filename`. 661 | * 662 | * @param filename 663 | */ 664 | attachment(filename?: string): Response; 665 | 666 | /** 667 | * Set header `field` to `val`, or pass 668 | * an object of header fields. 669 | * 670 | * Examples: 671 | * 672 | * res.set('Foo', ['bar', 'baz']); 673 | * res.set('Accept', 'application/json'); 674 | * res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' }); 675 | * 676 | * Aliased as `res.header()`. 677 | */ 678 | set(field: any): Response; 679 | set(field: string, value?: string): Response; 680 | 681 | header(field: any): Response; 682 | header(field: string, value?: string): Response; 683 | 684 | // Property indicating if HTTP headers has been sent for the response. 685 | headersSent: boolean; 686 | 687 | /** 688 | * Get value for header `field`. 689 | * 690 | * @param field 691 | */ 692 | get (field: string): string; 693 | 694 | /** 695 | * Clear cookie `name`. 696 | * 697 | * @param name 698 | * @param options 699 | */ 700 | clearCookie(name: string, options?: any): Response; 701 | 702 | /** 703 | * Set cookie `name` to `val`, with the given `options`. 704 | * 705 | * Options: 706 | * 707 | * - `maxAge` max-age in milliseconds, converted to `expires` 708 | * - `signed` sign the cookie 709 | * - `path` defaults to "/" 710 | * 711 | * Examples: 712 | * 713 | * // "Remember Me" for 15 minutes 714 | * res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true }); 715 | * 716 | * // save as above 717 | * res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }) 718 | */ 719 | cookie(name: string, val: string, options: CookieOptions): Response; 720 | cookie(name: string, val: any, options: CookieOptions): Response; 721 | cookie(name: string, val: any): Response; 722 | 723 | /** 724 | * Set the location header to `url`. 725 | * 726 | * The given `url` can also be the name of a mapped url, for 727 | * example by default express supports "back" which redirects 728 | * to the _Referrer_ or _Referer_ headers or "/". 729 | * 730 | * Examples: 731 | * 732 | * res.location('/foo/bar').; 733 | * res.location('http://example.com'); 734 | * res.location('../login'); // /blog/post/1 -> /blog/login 735 | * 736 | * Mounting: 737 | * 738 | * When an application is mounted and `res.location()` 739 | * is given a path that does _not_ lead with "/" it becomes 740 | * relative to the mount-point. For example if the application 741 | * is mounted at "/blog", the following would become "/blog/login". 742 | * 743 | * res.location('login'); 744 | * 745 | * While the leading slash would result in a location of "/login": 746 | * 747 | * res.location('/login'); 748 | * 749 | * @param url 750 | */ 751 | location(url: string): Response; 752 | 753 | /** 754 | * Redirect to the given `url` with optional response `status` 755 | * defaulting to 302. 756 | * 757 | * The resulting `url` is determined by `res.location()`, so 758 | * it will play nicely with mounted apps, relative paths, 759 | * `"back"` etc. 760 | * 761 | * Examples: 762 | * 763 | * res.redirect('/foo/bar'); 764 | * res.redirect('http://example.com'); 765 | * res.redirect(301, 'http://example.com'); 766 | * res.redirect('http://example.com', 301); 767 | * res.redirect('../login'); // /blog/post/1 -> /blog/login 768 | */ 769 | redirect(url: string): void; 770 | redirect(status: number, url: string): void; 771 | redirect(url: string, status: number): void; 772 | 773 | /** 774 | * Render `view` with the given `options` and optional callback `fn`. 775 | * When a callback function is given a response will _not_ be made 776 | * automatically, otherwise a response of _200_ and _text/html_ is given. 777 | * 778 | * Options: 779 | * 780 | * - `cache` boolean hinting to the engine it should cache 781 | * - `filename` filename of the view being rendered 782 | */ 783 | render(view: string, options?: Object, callback?: (err: Error, html: string) => void ): void; 784 | render(view: string, callback?: (err: Error, html: string) => void ): void; 785 | 786 | locals: any; 787 | 788 | charset: string; 789 | } 790 | 791 | interface ErrorRequestHandler { 792 | (err: any, req: Request, res: Response, next: Function): any; 793 | } 794 | 795 | interface RequestHandler { 796 | (req: Request, res: Response, next: Function): any; 797 | } 798 | 799 | interface Handler extends RequestHandler {} 800 | 801 | interface RequestParamHandler { 802 | (req: Request, res: Response, next: Function, param: any): any; 803 | } 804 | 805 | interface Application extends IRouter, Express.Application { 806 | /** 807 | * Initialize the server. 808 | * 809 | * - setup default configuration 810 | * - setup default middleware 811 | * - setup route reflection methods 812 | */ 813 | init(): void; 814 | 815 | /** 816 | * Initialize application configuration. 817 | */ 818 | defaultConfiguration(): void; 819 | 820 | /** 821 | * Register the given template engine callback `fn` 822 | * as `ext`. 823 | * 824 | * By default will `require()` the engine based on the 825 | * file extension. For example if you try to render 826 | * a "foo.jade" file Express will invoke the following internally: 827 | * 828 | * app.engine('jade', require('jade').__express); 829 | * 830 | * For engines that do not provide `.__express` out of the box, 831 | * or if you wish to "map" a different extension to the template engine 832 | * you may use this method. For example mapping the EJS template engine to 833 | * ".html" files: 834 | * 835 | * app.engine('html', require('ejs').renderFile); 836 | * 837 | * In this case EJS provides a `.renderFile()` method with 838 | * the same signature that Express expects: `(path, options, callback)`, 839 | * though note that it aliases this method as `ejs.__express` internally 840 | * so if you're using ".ejs" extensions you dont need to do anything. 841 | * 842 | * Some template engines do not follow this convention, the 843 | * [Consolidate.js](https://github.com/visionmedia/consolidate.js) 844 | * library was created to map all of node's popular template 845 | * engines to follow this convention, thus allowing them to 846 | * work seamlessly within Express. 847 | */ 848 | engine(ext: string, fn: Function): Application; 849 | 850 | /** 851 | * Assign `setting` to `val`, or return `setting`'s value. 852 | * 853 | * app.set('foo', 'bar'); 854 | * app.get('foo'); 855 | * // => "bar" 856 | * app.set('foo', ['bar', 'baz']); 857 | * app.get('foo'); 858 | * // => ["bar", "baz"] 859 | * 860 | * Mounted servers inherit their parent server's settings. 861 | * 862 | * @param setting 863 | * @param val 864 | */ 865 | set(setting: string, val: any): Application; 866 | get: { 867 | (name: string): any; // Getter 868 | (name: string, ...handlers: RequestHandler[]): Application; 869 | (name: RegExp, ...handlers: RequestHandler[]): Application; 870 | }; 871 | 872 | /** 873 | * Return the app's absolute pathname 874 | * based on the parent(s) that have 875 | * mounted it. 876 | * 877 | * For example if the application was 878 | * mounted as "/admin", which itself 879 | * was mounted as "/blog" then the 880 | * return value would be "/blog/admin". 881 | */ 882 | path(): string; 883 | 884 | /** 885 | * Check if `setting` is enabled (truthy). 886 | * 887 | * app.enabled('foo') 888 | * // => false 889 | * 890 | * app.enable('foo') 891 | * app.enabled('foo') 892 | * // => true 893 | */ 894 | enabled(setting: string): boolean; 895 | 896 | /** 897 | * Check if `setting` is disabled. 898 | * 899 | * app.disabled('foo') 900 | * // => true 901 | * 902 | * app.enable('foo') 903 | * app.disabled('foo') 904 | * // => false 905 | * 906 | * @param setting 907 | */ 908 | disabled(setting: string): boolean; 909 | 910 | /** 911 | * Enable `setting`. 912 | * 913 | * @param setting 914 | */ 915 | enable(setting: string): Application; 916 | 917 | /** 918 | * Disable `setting`. 919 | * 920 | * @param setting 921 | */ 922 | disable(setting: string): Application; 923 | 924 | /** 925 | * Configure callback for zero or more envs, 926 | * when no `env` is specified that callback will 927 | * be invoked for all environments. Any combination 928 | * can be used multiple times, in any order desired. 929 | * 930 | * Examples: 931 | * 932 | * app.configure(function(){ 933 | * // executed for all envs 934 | * }); 935 | * 936 | * app.configure('stage', function(){ 937 | * // executed staging env 938 | * }); 939 | * 940 | * app.configure('stage', 'production', function(){ 941 | * // executed for stage and production 942 | * }); 943 | * 944 | * Note: 945 | * 946 | * These callbacks are invoked immediately, and 947 | * are effectively sugar for the following: 948 | * 949 | * var env = process.env.NODE_ENV || 'development'; 950 | * 951 | * switch (env) { 952 | * case 'development': 953 | * ... 954 | * break; 955 | * case 'stage': 956 | * ... 957 | * break; 958 | * case 'production': 959 | * ... 960 | * break; 961 | * } 962 | * 963 | * @param env 964 | * @param fn 965 | */ 966 | configure(fn: Function): Application; 967 | configure(env0: string, fn: Function): Application; 968 | configure(env0: string, env1: string, fn: Function): Application; 969 | configure(env0: string, env1: string, env2: string, fn: Function): Application; 970 | configure(env0: string, env1: string, env2: string, env3: string, fn: Function): Application; 971 | configure(env0: string, env1: string, env2: string, env3: string, env4: string, fn: Function): Application; 972 | 973 | /** 974 | * Render the given view `name` name with `options` 975 | * and a callback accepting an error and the 976 | * rendered template string. 977 | * 978 | * Example: 979 | * 980 | * app.render('email', { name: 'Tobi' }, function(err, html){ 981 | * // ... 982 | * }) 983 | * 984 | * @param name 985 | * @param options or fn 986 | * @param fn 987 | */ 988 | render(name: string, options?: Object, callback?: (err: Error, html: string) => void): void; 989 | render(name: string, callback: (err: Error, html: string) => void): void; 990 | 991 | 992 | /** 993 | * Listen for connections. 994 | * 995 | * A node `http.Server` is returned, with this 996 | * application (which is a `Function`) as its 997 | * callback. If you wish to create both an HTTP 998 | * and HTTPS server you may do so with the "http" 999 | * and "https" modules as shown here: 1000 | * 1001 | * var http = require('http') 1002 | * , https = require('https') 1003 | * , express = require('express') 1004 | * , app = express(); 1005 | * 1006 | * http.createServer(app).listen(80); 1007 | * https.createServer({ ... }, app).listen(443); 1008 | */ 1009 | listen(port: number, hostname: string, backlog: number, callback?: Function): http.Server; 1010 | listen(port: number, hostname: string, callback?: Function): http.Server; 1011 | listen(port: number, callback?: Function): http.Server; 1012 | listen(path: string, callback?: Function): http.Server; 1013 | listen(handle: any, listeningListener?: Function): http.Server; 1014 | 1015 | route(path: string): IRoute; 1016 | 1017 | router: string; 1018 | 1019 | settings: any; 1020 | 1021 | resource: any; 1022 | 1023 | map: any; 1024 | 1025 | locals: any; 1026 | 1027 | /** 1028 | * The app.routes object houses all of the routes defined mapped by the 1029 | * associated HTTP verb. This object may be used for introspection 1030 | * capabilities, for example Express uses this internally not only for 1031 | * routing but to provide default OPTIONS behaviour unless app.options() 1032 | * is used. Your application or framework may also remove routes by 1033 | * simply by removing them from this object. 1034 | */ 1035 | routes: any; 1036 | } 1037 | 1038 | interface Express extends Application { 1039 | /** 1040 | * Framework version. 1041 | */ 1042 | version: string; 1043 | 1044 | /** 1045 | * Expose mime. 1046 | */ 1047 | mime: string; 1048 | 1049 | (): Application; 1050 | 1051 | /** 1052 | * Create an express application. 1053 | */ 1054 | createApplication(): Application; 1055 | 1056 | createServer(): Application; 1057 | 1058 | application: any; 1059 | 1060 | request: Request; 1061 | 1062 | response: Response; 1063 | } 1064 | 1065 | /** 1066 | * Static: 1067 | * 1068 | * Static file server with the given `root` path. 1069 | * 1070 | * Examples: 1071 | * 1072 | * var oneDay = 86400000; 1073 | * 1074 | * connect() 1075 | * .use(connect.static(__dirname + '/public')) 1076 | * 1077 | * connect() 1078 | * .use(connect.static(__dirname + '/public', { maxAge: oneDay })) 1079 | * 1080 | * Options: 1081 | * 1082 | * - `maxAge` Browser cache maxAge in milliseconds. defaults to 0 1083 | * - `hidden` Allow transfer of hidden files. defaults to false 1084 | * - `redirect` Redirect to trailing "/" when the pathname is a dir. defaults to true 1085 | * 1086 | * @param root 1087 | * @param options 1088 | */ 1089 | function static(root: string, options?: any): RequestHandler; 1090 | } 1091 | 1092 | export = e; 1093 | } 1094 | -------------------------------------------------------------------------------- /typings/handlebars/handlebars.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Handlebars v3.0.3 2 | // Project: http://handlebarsjs.com/ 3 | // Definitions by: Boris Yankov 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | 7 | declare module Handlebars { 8 | export function registerHelper(name: string, fn: Function, inverse?: boolean): void; 9 | export function registerPartial(name: string, str: any): void; 10 | export function K(): void; 11 | export function createFrame(object: any): any; 12 | export function Exception(message: string): void; 13 | export function log(level: number, obj: any): void; 14 | export function parse(input: string): hbs.AST.Program; 15 | export function compile(input: any, options?: any): HandlebarsTemplateDelegate; 16 | 17 | export var SafeString: typeof hbs.SafeString; 18 | export var Utils: typeof hbs.Utils; 19 | export var logger: Logger; 20 | export var templates: HandlebarsTemplates; 21 | export var helpers: any; 22 | 23 | export module AST { 24 | export var helpers: hbs.AST.helpers; 25 | } 26 | 27 | interface ICompiler { 28 | accept(node: hbs.AST.Node): void; 29 | Program(program: hbs.AST.Program): void; 30 | BlockStatement(block: hbs.AST.BlockStatement): void; 31 | PartialStatement(partial: hbs.AST.PartialStatement): void; 32 | MustacheStatement(mustache: hbs.AST.MustacheStatement): void; 33 | ContentStatement(content: hbs.AST.ContentStatement): void; 34 | CommentStatement(comment?: hbs.AST.CommentStatement): void; 35 | SubExpression(sexpr: hbs.AST.SubExpression): void; 36 | PathExpression(path: hbs.AST.PathExpression): void; 37 | StringLiteral(str: hbs.AST.StringLiteral): void; 38 | NumberLiteral(num: hbs.AST.NumberLiteral): void; 39 | BooleanLiteral(bool: hbs.AST.BooleanLiteral): void; 40 | UndefinedLiteral(): void; 41 | NullLiteral(): void; 42 | Hash(hash: hbs.AST.Hash): void; 43 | } 44 | 45 | export class Visitor implements ICompiler { 46 | accept(node: hbs.AST.Node): void; 47 | acceptKey(node: hbs.AST.Node, name: string): void; 48 | acceptArray(arr: hbs.AST.Expression[]): void; 49 | Program(program: hbs.AST.Program): void; 50 | BlockStatement(block: hbs.AST.BlockStatement): void; 51 | PartialStatement(partial: hbs.AST.PartialStatement): void; 52 | MustacheStatement(mustache: hbs.AST.MustacheStatement): void; 53 | ContentStatement(content: hbs.AST.ContentStatement): void; 54 | CommentStatement(comment?: hbs.AST.CommentStatement): void; 55 | SubExpression(sexpr: hbs.AST.SubExpression): void; 56 | PathExpression(path: hbs.AST.PathExpression): void; 57 | StringLiteral(str: hbs.AST.StringLiteral): void; 58 | NumberLiteral(num: hbs.AST.NumberLiteral): void; 59 | BooleanLiteral(bool: hbs.AST.BooleanLiteral): void; 60 | UndefinedLiteral(): void; 61 | NullLiteral(): void; 62 | Hash(hash: hbs.AST.Hash): void; 63 | } 64 | } 65 | 66 | /** 67 | * Implement this interface on your MVW/MVVM/MVC views such as Backbone.View 68 | **/ 69 | interface HandlebarsTemplatable { 70 | template: HandlebarsTemplateDelegate; 71 | } 72 | 73 | interface HandlebarsTemplateDelegate { 74 | (context: any, options?: any): string; 75 | } 76 | 77 | interface HandlebarsTemplates { 78 | [index: string]: HandlebarsTemplateDelegate; 79 | } 80 | 81 | declare module hbs { 82 | class SafeString { 83 | constructor(str: string); 84 | static toString(): string; 85 | } 86 | 87 | module Utils { 88 | function escapeExpression(str: string): string; 89 | } 90 | } 91 | 92 | interface Logger { 93 | DEBUG: number; 94 | INFO: number; 95 | WARN: number; 96 | ERROR: number; 97 | level: number; 98 | 99 | methodMap: { [level: number]: string }; 100 | 101 | log(level: number, obj: string): void; 102 | } 103 | 104 | declare module hbs { 105 | module AST { 106 | interface Node { 107 | type: string; 108 | loc: SourceLocation; 109 | } 110 | 111 | interface SourceLocation { 112 | source: string; 113 | start: Position; 114 | end: Position; 115 | } 116 | 117 | interface Position { 118 | line: number; 119 | column: number; 120 | } 121 | 122 | interface Program extends Node { 123 | body: Statement[]; 124 | blockParams: string[]; 125 | } 126 | 127 | interface Statement extends Node {} 128 | 129 | interface MustacheStatement extends Statement { 130 | path: PathExpression | Literal; 131 | params: Expression[]; 132 | hash: Hash; 133 | escaped: boolean; 134 | strip: StripFlags; 135 | } 136 | 137 | interface BlockStatement extends Statement { 138 | path: PathExpression; 139 | params: Expression[]; 140 | hash: Hash; 141 | program: Program; 142 | inverse: Program; 143 | openStrip: StripFlags; 144 | inverseStrip: StripFlags; 145 | closeStrip: StripFlags; 146 | } 147 | 148 | interface PartialStatement extends Statement { 149 | name: PathExpression | SubExpression; 150 | params: Expression[]; 151 | hash: Hash; 152 | indent: string; 153 | strip: StripFlags; 154 | } 155 | 156 | interface ContentStatement extends Statement { 157 | value: string; 158 | original: StripFlags; 159 | } 160 | 161 | interface CommentStatement extends Statement { 162 | value: string; 163 | strip: StripFlags; 164 | } 165 | 166 | interface Expression extends Node {} 167 | 168 | interface SubExpression extends Expression { 169 | path: PathExpression; 170 | params: Expression[]; 171 | hash: Hash; 172 | } 173 | 174 | interface PathExpression extends Expression { 175 | data: boolean; 176 | depth: number; 177 | parts: string[]; 178 | original: string; 179 | } 180 | 181 | interface Literal extends Expression {} 182 | interface StringLiteral extends Literal { 183 | value: string; 184 | original: string; 185 | } 186 | 187 | interface BooleanLiteral extends Literal { 188 | value: boolean; 189 | original: boolean; 190 | } 191 | 192 | interface NumberLiteral extends Literal { 193 | value: number; 194 | original: number; 195 | } 196 | 197 | interface UndefinedLiteral extends Literal {} 198 | 199 | interface NullLiteral extends Literal {} 200 | 201 | interface Hash extends Node { 202 | pairs: HashPair[]; 203 | } 204 | 205 | interface HashPair extends Node { 206 | key: string; 207 | value: Expression; 208 | } 209 | 210 | interface StripFlags { 211 | open: boolean; 212 | close: boolean; 213 | } 214 | 215 | interface helpers { 216 | helperExpression(node: Node): boolean; 217 | scopeId(path: PathExpression): boolean; 218 | simpleId(path: PathExpression): boolean; 219 | } 220 | } 221 | } 222 | 223 | declare module "handlebars" { 224 | export = Handlebars; 225 | } 226 | -------------------------------------------------------------------------------- /typings/node/node.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Node.js v0.12.0 2 | // Project: http://nodejs.org/ 3 | // Definitions by: Microsoft TypeScript , DefinitelyTyped 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /************************************************ 7 | * * 8 | * Node.js v0.12.0 API * 9 | * * 10 | ************************************************/ 11 | 12 | /************************************************ 13 | * * 14 | * GLOBAL * 15 | * * 16 | ************************************************/ 17 | declare var process: NodeJS.Process; 18 | declare var global: NodeJS.Global; 19 | 20 | declare var __filename: string; 21 | declare var __dirname: string; 22 | 23 | declare function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; 24 | declare function clearTimeout(timeoutId: NodeJS.Timer): void; 25 | declare function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; 26 | declare function clearInterval(intervalId: NodeJS.Timer): void; 27 | declare function setImmediate(callback: (...args: any[]) => void, ...args: any[]): any; 28 | declare function clearImmediate(immediateId: any): void; 29 | 30 | declare var require: { 31 | (id: string): any; 32 | resolve(id:string): string; 33 | cache: any; 34 | extensions: any; 35 | main: any; 36 | }; 37 | 38 | declare var module: { 39 | exports: any; 40 | require(id: string): any; 41 | id: string; 42 | filename: string; 43 | loaded: boolean; 44 | parent: any; 45 | children: any[]; 46 | }; 47 | 48 | // Same as module.exports 49 | declare var exports: any; 50 | declare var SlowBuffer: { 51 | new (str: string, encoding?: string): Buffer; 52 | new (size: number): Buffer; 53 | new (size: Uint8Array): Buffer; 54 | new (array: any[]): Buffer; 55 | prototype: Buffer; 56 | isBuffer(obj: any): boolean; 57 | byteLength(string: string, encoding?: string): number; 58 | concat(list: Buffer[], totalLength?: number): Buffer; 59 | }; 60 | 61 | 62 | // Buffer class 63 | interface Buffer extends NodeBuffer {} 64 | declare var Buffer: { 65 | new (str: string, encoding?: string): Buffer; 66 | new (size: number): Buffer; 67 | new (size: Uint8Array): Buffer; 68 | new (array: any[]): Buffer; 69 | prototype: Buffer; 70 | isBuffer(obj: any): boolean; 71 | byteLength(string: string, encoding?: string): number; 72 | concat(list: Buffer[], totalLength?: number): Buffer; 73 | }; 74 | 75 | /************************************************ 76 | * * 77 | * GLOBAL INTERFACES * 78 | * * 79 | ************************************************/ 80 | declare module NodeJS { 81 | export interface ErrnoException extends Error { 82 | errno?: number; 83 | code?: string; 84 | path?: string; 85 | syscall?: string; 86 | } 87 | 88 | export interface EventEmitter { 89 | addListener(event: string, listener: Function): EventEmitter; 90 | on(event: string, listener: Function): EventEmitter; 91 | once(event: string, listener: Function): EventEmitter; 92 | removeListener(event: string, listener: Function): EventEmitter; 93 | removeAllListeners(event?: string): EventEmitter; 94 | setMaxListeners(n: number): void; 95 | listeners(event: string): Function[]; 96 | emit(event: string, ...args: any[]): boolean; 97 | } 98 | 99 | export interface ReadableStream extends EventEmitter { 100 | readable: boolean; 101 | read(size?: number): string|Buffer; 102 | setEncoding(encoding: string): void; 103 | pause(): void; 104 | resume(): void; 105 | pipe(destination: T, options?: { end?: boolean; }): T; 106 | unpipe(destination?: T): void; 107 | unshift(chunk: string): void; 108 | unshift(chunk: Buffer): void; 109 | wrap(oldStream: ReadableStream): ReadableStream; 110 | } 111 | 112 | export interface WritableStream extends EventEmitter { 113 | writable: boolean; 114 | write(buffer: Buffer, cb?: Function): boolean; 115 | write(str: string, cb?: Function): boolean; 116 | write(str: string, encoding?: string, cb?: Function): boolean; 117 | end(): void; 118 | end(buffer: Buffer, cb?: Function): void; 119 | end(str: string, cb?: Function): void; 120 | end(str: string, encoding?: string, cb?: Function): void; 121 | } 122 | 123 | export interface ReadWriteStream extends ReadableStream, WritableStream {} 124 | 125 | export interface Process extends EventEmitter { 126 | stdout: WritableStream; 127 | stderr: WritableStream; 128 | stdin: ReadableStream; 129 | argv: string[]; 130 | execPath: string; 131 | abort(): void; 132 | chdir(directory: string): void; 133 | cwd(): string; 134 | env: any; 135 | exit(code?: number): void; 136 | getgid(): number; 137 | setgid(id: number): void; 138 | setgid(id: string): void; 139 | getuid(): number; 140 | setuid(id: number): void; 141 | setuid(id: string): void; 142 | version: string; 143 | versions: { 144 | http_parser: string; 145 | node: string; 146 | v8: string; 147 | ares: string; 148 | uv: string; 149 | zlib: string; 150 | openssl: string; 151 | }; 152 | config: { 153 | target_defaults: { 154 | cflags: any[]; 155 | default_configuration: string; 156 | defines: string[]; 157 | include_dirs: string[]; 158 | libraries: string[]; 159 | }; 160 | variables: { 161 | clang: number; 162 | host_arch: string; 163 | node_install_npm: boolean; 164 | node_install_waf: boolean; 165 | node_prefix: string; 166 | node_shared_openssl: boolean; 167 | node_shared_v8: boolean; 168 | node_shared_zlib: boolean; 169 | node_use_dtrace: boolean; 170 | node_use_etw: boolean; 171 | node_use_openssl: boolean; 172 | target_arch: string; 173 | v8_no_strict_aliasing: number; 174 | v8_use_snapshot: boolean; 175 | visibility: string; 176 | }; 177 | }; 178 | kill(pid: number, signal?: string): void; 179 | pid: number; 180 | title: string; 181 | arch: string; 182 | platform: string; 183 | memoryUsage(): { rss: number; heapTotal: number; heapUsed: number; }; 184 | nextTick(callback: Function): void; 185 | umask(mask?: number): number; 186 | uptime(): number; 187 | hrtime(time?:number[]): number[]; 188 | 189 | // Worker 190 | send?(message: any, sendHandle?: any): void; 191 | } 192 | 193 | export interface Global { 194 | Array: typeof Array; 195 | ArrayBuffer: typeof ArrayBuffer; 196 | Boolean: typeof Boolean; 197 | Buffer: typeof Buffer; 198 | DataView: typeof DataView; 199 | Date: typeof Date; 200 | Error: typeof Error; 201 | EvalError: typeof EvalError; 202 | Float32Array: typeof Float32Array; 203 | Float64Array: typeof Float64Array; 204 | Function: typeof Function; 205 | GLOBAL: Global; 206 | Infinity: typeof Infinity; 207 | Int16Array: typeof Int16Array; 208 | Int32Array: typeof Int32Array; 209 | Int8Array: typeof Int8Array; 210 | Intl: typeof Intl; 211 | JSON: typeof JSON; 212 | Map: typeof Map; 213 | Math: typeof Math; 214 | NaN: typeof NaN; 215 | Number: typeof Number; 216 | Object: typeof Object; 217 | Promise: Function; 218 | RangeError: typeof RangeError; 219 | ReferenceError: typeof ReferenceError; 220 | RegExp: typeof RegExp; 221 | Set: typeof Set; 222 | String: typeof String; 223 | Symbol: Function; 224 | SyntaxError: typeof SyntaxError; 225 | TypeError: typeof TypeError; 226 | URIError: typeof URIError; 227 | Uint16Array: typeof Uint16Array; 228 | Uint32Array: typeof Uint32Array; 229 | Uint8Array: typeof Uint8Array; 230 | Uint8ClampedArray: Function; 231 | WeakMap: typeof WeakMap; 232 | WeakSet: Function; 233 | clearImmediate: (immediateId: any) => void; 234 | clearInterval: (intervalId: NodeJS.Timer) => void; 235 | clearTimeout: (timeoutId: NodeJS.Timer) => void; 236 | console: typeof console; 237 | decodeURI: typeof decodeURI; 238 | decodeURIComponent: typeof decodeURIComponent; 239 | encodeURI: typeof encodeURI; 240 | encodeURIComponent: typeof encodeURIComponent; 241 | escape: (str: string) => string; 242 | eval: typeof eval; 243 | global: Global; 244 | isFinite: typeof isFinite; 245 | isNaN: typeof isNaN; 246 | parseFloat: typeof parseFloat; 247 | parseInt: typeof parseInt; 248 | process: Process; 249 | root: Global; 250 | setImmediate: (callback: (...args: any[]) => void, ...args: any[]) => any; 251 | setInterval: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timer; 252 | setTimeout: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timer; 253 | undefined: typeof undefined; 254 | unescape: (str: string) => string; 255 | } 256 | 257 | export interface Timer { 258 | ref() : void; 259 | unref() : void; 260 | } 261 | } 262 | 263 | /** 264 | * @deprecated 265 | */ 266 | interface NodeBuffer { 267 | [index: number]: number; 268 | write(string: string, offset?: number, length?: number, encoding?: string): number; 269 | toString(encoding?: string, start?: number, end?: number): string; 270 | toJSON(): any; 271 | length: number; 272 | copy(targetBuffer: Buffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number; 273 | slice(start?: number, end?: number): Buffer; 274 | readUInt8(offset: number, noAsset?: boolean): number; 275 | readUInt16LE(offset: number, noAssert?: boolean): number; 276 | readUInt16BE(offset: number, noAssert?: boolean): number; 277 | readUInt32LE(offset: number, noAssert?: boolean): number; 278 | readUInt32BE(offset: number, noAssert?: boolean): number; 279 | readInt8(offset: number, noAssert?: boolean): number; 280 | readInt16LE(offset: number, noAssert?: boolean): number; 281 | readInt16BE(offset: number, noAssert?: boolean): number; 282 | readInt32LE(offset: number, noAssert?: boolean): number; 283 | readInt32BE(offset: number, noAssert?: boolean): number; 284 | readFloatLE(offset: number, noAssert?: boolean): number; 285 | readFloatBE(offset: number, noAssert?: boolean): number; 286 | readDoubleLE(offset: number, noAssert?: boolean): number; 287 | readDoubleBE(offset: number, noAssert?: boolean): number; 288 | writeUInt8(value: number, offset: number, noAssert?: boolean): void; 289 | writeUInt16LE(value: number, offset: number, noAssert?: boolean): void; 290 | writeUInt16BE(value: number, offset: number, noAssert?: boolean): void; 291 | writeUInt32LE(value: number, offset: number, noAssert?: boolean): void; 292 | writeUInt32BE(value: number, offset: number, noAssert?: boolean): void; 293 | writeInt8(value: number, offset: number, noAssert?: boolean): void; 294 | writeInt16LE(value: number, offset: number, noAssert?: boolean): void; 295 | writeInt16BE(value: number, offset: number, noAssert?: boolean): void; 296 | writeInt32LE(value: number, offset: number, noAssert?: boolean): void; 297 | writeInt32BE(value: number, offset: number, noAssert?: boolean): void; 298 | writeFloatLE(value: number, offset: number, noAssert?: boolean): void; 299 | writeFloatBE(value: number, offset: number, noAssert?: boolean): void; 300 | writeDoubleLE(value: number, offset: number, noAssert?: boolean): void; 301 | writeDoubleBE(value: number, offset: number, noAssert?: boolean): void; 302 | fill(value: any, offset?: number, end?: number): void; 303 | } 304 | 305 | /************************************************ 306 | * * 307 | * MODULES * 308 | * * 309 | ************************************************/ 310 | declare module "buffer" { 311 | export var INSPECT_MAX_BYTES: number; 312 | } 313 | 314 | declare module "querystring" { 315 | export function stringify(obj: any, sep?: string, eq?: string): string; 316 | export function parse(str: string, sep?: string, eq?: string, options?: { maxKeys?: number; }): any; 317 | export function escape(str: string): string; 318 | export function unescape(str: string): string; 319 | } 320 | 321 | declare module "events" { 322 | export class EventEmitter implements NodeJS.EventEmitter { 323 | static listenerCount(emitter: EventEmitter, event: string): number; 324 | 325 | addListener(event: string, listener: Function): EventEmitter; 326 | on(event: string, listener: Function): EventEmitter; 327 | once(event: string, listener: Function): EventEmitter; 328 | removeListener(event: string, listener: Function): EventEmitter; 329 | removeAllListeners(event?: string): EventEmitter; 330 | setMaxListeners(n: number): void; 331 | listeners(event: string): Function[]; 332 | emit(event: string, ...args: any[]): boolean; 333 | } 334 | } 335 | 336 | declare module "http" { 337 | import events = require("events"); 338 | import net = require("net"); 339 | import stream = require("stream"); 340 | 341 | export interface Server extends events.EventEmitter { 342 | listen(port: number, hostname?: string, backlog?: number, callback?: Function): Server; 343 | listen(path: string, callback?: Function): Server; 344 | listen(handle: any, listeningListener?: Function): Server; 345 | close(cb?: any): Server; 346 | address(): { port: number; family: string; address: string; }; 347 | maxHeadersCount: number; 348 | } 349 | /** 350 | * @deprecated Use IncomingMessage 351 | */ 352 | export interface ServerRequest extends IncomingMessage { 353 | connection: net.Socket; 354 | } 355 | export interface ServerResponse extends events.EventEmitter, stream.Writable { 356 | // Extended base methods 357 | write(buffer: Buffer): boolean; 358 | write(buffer: Buffer, cb?: Function): boolean; 359 | write(str: string, cb?: Function): boolean; 360 | write(str: string, encoding?: string, cb?: Function): boolean; 361 | write(str: string, encoding?: string, fd?: string): boolean; 362 | 363 | writeContinue(): void; 364 | writeHead(statusCode: number, reasonPhrase?: string, headers?: any): void; 365 | writeHead(statusCode: number, headers?: any): void; 366 | statusCode: number; 367 | setHeader(name: string, value: string): void; 368 | sendDate: boolean; 369 | getHeader(name: string): string; 370 | removeHeader(name: string): void; 371 | write(chunk: any, encoding?: string): any; 372 | addTrailers(headers: any): void; 373 | 374 | // Extended base methods 375 | end(): void; 376 | end(buffer: Buffer, cb?: Function): void; 377 | end(str: string, cb?: Function): void; 378 | end(str: string, encoding?: string, cb?: Function): void; 379 | end(data?: any, encoding?: string): void; 380 | } 381 | export interface ClientRequest extends events.EventEmitter, stream.Writable { 382 | // Extended base methods 383 | write(buffer: Buffer): boolean; 384 | write(buffer: Buffer, cb?: Function): boolean; 385 | write(str: string, cb?: Function): boolean; 386 | write(str: string, encoding?: string, cb?: Function): boolean; 387 | write(str: string, encoding?: string, fd?: string): boolean; 388 | 389 | write(chunk: any, encoding?: string): void; 390 | abort(): void; 391 | setTimeout(timeout: number, callback?: Function): void; 392 | setNoDelay(noDelay?: boolean): void; 393 | setSocketKeepAlive(enable?: boolean, initialDelay?: number): void; 394 | 395 | // Extended base methods 396 | end(): void; 397 | end(buffer: Buffer, cb?: Function): void; 398 | end(str: string, cb?: Function): void; 399 | end(str: string, encoding?: string, cb?: Function): void; 400 | end(data?: any, encoding?: string): void; 401 | } 402 | export interface IncomingMessage extends events.EventEmitter, stream.Readable { 403 | httpVersion: string; 404 | headers: any; 405 | rawHeaders: string[]; 406 | trailers: any; 407 | rawTrailers: any; 408 | setTimeout(msecs: number, callback: Function): NodeJS.Timer; 409 | /** 410 | * Only valid for request obtained from http.Server. 411 | */ 412 | method?: string; 413 | /** 414 | * Only valid for request obtained from http.Server. 415 | */ 416 | url?: string; 417 | /** 418 | * Only valid for response obtained from http.ClientRequest. 419 | */ 420 | statusCode?: number; 421 | /** 422 | * Only valid for response obtained from http.ClientRequest. 423 | */ 424 | statusMessage?: string; 425 | socket: net.Socket; 426 | } 427 | /** 428 | * @deprecated Use IncomingMessage 429 | */ 430 | export interface ClientResponse extends IncomingMessage { } 431 | 432 | export interface AgentOptions { 433 | /** 434 | * Keep sockets around in a pool to be used by other requests in the future. Default = false 435 | */ 436 | keepAlive?: boolean; 437 | /** 438 | * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000. 439 | * Only relevant if keepAlive is set to true. 440 | */ 441 | keepAliveMsecs?: number; 442 | /** 443 | * Maximum number of sockets to allow per host. Default for Node 0.10 is 5, default for Node 0.12 is Infinity 444 | */ 445 | maxSockets?: number; 446 | /** 447 | * Maximum number of sockets to leave open in a free state. Only relevant if keepAlive is set to true. Default = 256. 448 | */ 449 | maxFreeSockets?: number; 450 | } 451 | 452 | export class Agent { 453 | maxSockets: number; 454 | sockets: any; 455 | requests: any; 456 | 457 | constructor(opts?: AgentOptions); 458 | 459 | /** 460 | * Destroy any sockets that are currently in use by the agent. 461 | * It is usually not necessary to do this. However, if you are using an agent with KeepAlive enabled, 462 | * then it is best to explicitly shut down the agent when you know that it will no longer be used. Otherwise, 463 | * sockets may hang open for quite a long time before the server terminates them. 464 | */ 465 | destroy(): void; 466 | } 467 | 468 | export var STATUS_CODES: { 469 | [errorCode: number]: string; 470 | [errorCode: string]: string; 471 | }; 472 | export function createServer(requestListener?: (request: IncomingMessage, response: ServerResponse) =>void ): Server; 473 | export function createClient(port?: number, host?: string): any; 474 | export function request(options: any, callback?: (res: IncomingMessage) => void): ClientRequest; 475 | export function get(options: any, callback?: (res: IncomingMessage) => void): ClientRequest; 476 | export var globalAgent: Agent; 477 | } 478 | 479 | declare module "cluster" { 480 | import child = require("child_process"); 481 | import events = require("events"); 482 | 483 | export interface ClusterSettings { 484 | exec?: string; 485 | args?: string[]; 486 | silent?: boolean; 487 | } 488 | 489 | export class Worker extends events.EventEmitter { 490 | id: string; 491 | process: child.ChildProcess; 492 | suicide: boolean; 493 | send(message: any, sendHandle?: any): void; 494 | kill(signal?: string): void; 495 | destroy(signal?: string): void; 496 | disconnect(): void; 497 | } 498 | 499 | export var settings: ClusterSettings; 500 | export var isMaster: boolean; 501 | export var isWorker: boolean; 502 | export function setupMaster(settings?: ClusterSettings): void; 503 | export function fork(env?: any): Worker; 504 | export function disconnect(callback?: Function): void; 505 | export var worker: Worker; 506 | export var workers: Worker[]; 507 | 508 | // Event emitter 509 | export function addListener(event: string, listener: Function): void; 510 | export function on(event: string, listener: Function): any; 511 | export function once(event: string, listener: Function): void; 512 | export function removeListener(event: string, listener: Function): void; 513 | export function removeAllListeners(event?: string): void; 514 | export function setMaxListeners(n: number): void; 515 | export function listeners(event: string): Function[]; 516 | export function emit(event: string, ...args: any[]): boolean; 517 | } 518 | 519 | declare module "zlib" { 520 | import stream = require("stream"); 521 | export interface ZlibOptions { chunkSize?: number; windowBits?: number; level?: number; memLevel?: number; strategy?: number; dictionary?: any; } 522 | 523 | export interface Gzip extends stream.Transform { } 524 | export interface Gunzip extends stream.Transform { } 525 | export interface Deflate extends stream.Transform { } 526 | export interface Inflate extends stream.Transform { } 527 | export interface DeflateRaw extends stream.Transform { } 528 | export interface InflateRaw extends stream.Transform { } 529 | export interface Unzip extends stream.Transform { } 530 | 531 | export function createGzip(options?: ZlibOptions): Gzip; 532 | export function createGunzip(options?: ZlibOptions): Gunzip; 533 | export function createDeflate(options?: ZlibOptions): Deflate; 534 | export function createInflate(options?: ZlibOptions): Inflate; 535 | export function createDeflateRaw(options?: ZlibOptions): DeflateRaw; 536 | export function createInflateRaw(options?: ZlibOptions): InflateRaw; 537 | export function createUnzip(options?: ZlibOptions): Unzip; 538 | 539 | export function deflate(buf: Buffer, callback: (error: Error, result: any) =>void ): void; 540 | export function deflateRaw(buf: Buffer, callback: (error: Error, result: any) =>void ): void; 541 | export function gzip(buf: Buffer, callback: (error: Error, result: any) =>void ): void; 542 | export function gunzip(buf: Buffer, callback: (error: Error, result: any) =>void ): void; 543 | export function inflate(buf: Buffer, callback: (error: Error, result: any) =>void ): void; 544 | export function inflateRaw(buf: Buffer, callback: (error: Error, result: any) =>void ): void; 545 | export function unzip(buf: Buffer, callback: (error: Error, result: any) =>void ): void; 546 | 547 | // Constants 548 | export var Z_NO_FLUSH: number; 549 | export var Z_PARTIAL_FLUSH: number; 550 | export var Z_SYNC_FLUSH: number; 551 | export var Z_FULL_FLUSH: number; 552 | export var Z_FINISH: number; 553 | export var Z_BLOCK: number; 554 | export var Z_TREES: number; 555 | export var Z_OK: number; 556 | export var Z_STREAM_END: number; 557 | export var Z_NEED_DICT: number; 558 | export var Z_ERRNO: number; 559 | export var Z_STREAM_ERROR: number; 560 | export var Z_DATA_ERROR: number; 561 | export var Z_MEM_ERROR: number; 562 | export var Z_BUF_ERROR: number; 563 | export var Z_VERSION_ERROR: number; 564 | export var Z_NO_COMPRESSION: number; 565 | export var Z_BEST_SPEED: number; 566 | export var Z_BEST_COMPRESSION: number; 567 | export var Z_DEFAULT_COMPRESSION: number; 568 | export var Z_FILTERED: number; 569 | export var Z_HUFFMAN_ONLY: number; 570 | export var Z_RLE: number; 571 | export var Z_FIXED: number; 572 | export var Z_DEFAULT_STRATEGY: number; 573 | export var Z_BINARY: number; 574 | export var Z_TEXT: number; 575 | export var Z_ASCII: number; 576 | export var Z_UNKNOWN: number; 577 | export var Z_DEFLATED: number; 578 | export var Z_NULL: number; 579 | } 580 | 581 | declare module "os" { 582 | export function tmpdir(): string; 583 | export function hostname(): string; 584 | export function type(): string; 585 | export function platform(): string; 586 | export function arch(): string; 587 | export function release(): string; 588 | export function uptime(): number; 589 | export function loadavg(): number[]; 590 | export function totalmem(): number; 591 | export function freemem(): number; 592 | export function cpus(): { model: string; speed: number; times: { user: number; nice: number; sys: number; idle: number; irq: number; }; }[]; 593 | export function networkInterfaces(): any; 594 | export var EOL: string; 595 | } 596 | 597 | declare module "https" { 598 | import tls = require("tls"); 599 | import events = require("events"); 600 | import http = require("http"); 601 | 602 | export interface ServerOptions { 603 | pfx?: any; 604 | key?: any; 605 | passphrase?: string; 606 | cert?: any; 607 | ca?: any; 608 | crl?: any; 609 | ciphers?: string; 610 | honorCipherOrder?: boolean; 611 | requestCert?: boolean; 612 | rejectUnauthorized?: boolean; 613 | NPNProtocols?: any; 614 | SNICallback?: (servername: string) => any; 615 | } 616 | 617 | export interface RequestOptions { 618 | host?: string; 619 | hostname?: string; 620 | port?: number; 621 | path?: string; 622 | method?: string; 623 | headers?: any; 624 | auth?: string; 625 | agent?: any; 626 | pfx?: any; 627 | key?: any; 628 | passphrase?: string; 629 | cert?: any; 630 | ca?: any; 631 | ciphers?: string; 632 | rejectUnauthorized?: boolean; 633 | } 634 | 635 | export interface Agent { 636 | maxSockets: number; 637 | sockets: any; 638 | requests: any; 639 | } 640 | export var Agent: { 641 | new (options?: RequestOptions): Agent; 642 | }; 643 | export interface Server extends tls.Server { } 644 | export function createServer(options: ServerOptions, requestListener?: Function): Server; 645 | export function request(options: RequestOptions, callback?: (res: http.IncomingMessage) =>void ): http.ClientRequest; 646 | export function get(options: RequestOptions, callback?: (res: http.IncomingMessage) =>void ): http.ClientRequest; 647 | export var globalAgent: Agent; 648 | } 649 | 650 | declare module "punycode" { 651 | export function decode(string: string): string; 652 | export function encode(string: string): string; 653 | export function toUnicode(domain: string): string; 654 | export function toASCII(domain: string): string; 655 | export var ucs2: ucs2; 656 | interface ucs2 { 657 | decode(string: string): string; 658 | encode(codePoints: number[]): string; 659 | } 660 | export var version: any; 661 | } 662 | 663 | declare module "repl" { 664 | import stream = require("stream"); 665 | import events = require("events"); 666 | 667 | export interface ReplOptions { 668 | prompt?: string; 669 | input?: NodeJS.ReadableStream; 670 | output?: NodeJS.WritableStream; 671 | terminal?: boolean; 672 | eval?: Function; 673 | useColors?: boolean; 674 | useGlobal?: boolean; 675 | ignoreUndefined?: boolean; 676 | writer?: Function; 677 | } 678 | export function start(options: ReplOptions): events.EventEmitter; 679 | } 680 | 681 | declare module "readline" { 682 | import events = require("events"); 683 | import stream = require("stream"); 684 | 685 | export interface ReadLine extends events.EventEmitter { 686 | setPrompt(prompt: string, length: number): void; 687 | prompt(preserveCursor?: boolean): void; 688 | question(query: string, callback: Function): void; 689 | pause(): void; 690 | resume(): void; 691 | close(): void; 692 | write(data: any, key?: any): void; 693 | } 694 | export interface ReadLineOptions { 695 | input: NodeJS.ReadableStream; 696 | output: NodeJS.WritableStream; 697 | completer?: Function; 698 | terminal?: boolean; 699 | } 700 | export function createInterface(options: ReadLineOptions): ReadLine; 701 | } 702 | 703 | declare module "vm" { 704 | export interface Context { } 705 | export interface Script { 706 | runInThisContext(): void; 707 | runInNewContext(sandbox?: Context): void; 708 | } 709 | export function runInThisContext(code: string, filename?: string): void; 710 | export function runInNewContext(code: string, sandbox?: Context, filename?: string): void; 711 | export function runInContext(code: string, context: Context, filename?: string): void; 712 | export function createContext(initSandbox?: Context): Context; 713 | export function createScript(code: string, filename?: string): Script; 714 | } 715 | 716 | declare module "child_process" { 717 | import events = require("events"); 718 | import stream = require("stream"); 719 | 720 | export interface ChildProcess extends events.EventEmitter { 721 | stdin: stream.Writable; 722 | stdout: stream.Readable; 723 | stderr: stream.Readable; 724 | pid: number; 725 | kill(signal?: string): void; 726 | send(message: any, sendHandle?: any): void; 727 | disconnect(): void; 728 | } 729 | 730 | export function spawn(command: string, args?: string[], options?: { 731 | cwd?: string; 732 | stdio?: any; 733 | custom?: any; 734 | env?: any; 735 | detached?: boolean; 736 | }): ChildProcess; 737 | export function exec(command: string, options: { 738 | cwd?: string; 739 | stdio?: any; 740 | customFds?: any; 741 | env?: any; 742 | encoding?: string; 743 | timeout?: number; 744 | maxBuffer?: number; 745 | killSignal?: string; 746 | }, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess; 747 | export function exec(command: string, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess; 748 | export function execFile(file: string, 749 | callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess; 750 | export function execFile(file: string, args?: string[], 751 | callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess; 752 | export function execFile(file: string, args?: string[], options?: { 753 | cwd?: string; 754 | stdio?: any; 755 | customFds?: any; 756 | env?: any; 757 | encoding?: string; 758 | timeout?: number; 759 | maxBuffer?: string; 760 | killSignal?: string; 761 | }, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess; 762 | export function fork(modulePath: string, args?: string[], options?: { 763 | cwd?: string; 764 | env?: any; 765 | encoding?: string; 766 | }): ChildProcess; 767 | export function execSync(command: string, options?: { 768 | cwd?: string; 769 | input?: string|Buffer; 770 | stdio?: any; 771 | env?: any; 772 | uid?: number; 773 | gid?: number; 774 | timeout?: number; 775 | maxBuffer?: number; 776 | killSignal?: string; 777 | encoding?: string; 778 | }): ChildProcess; 779 | export function execFileSync(command: string, args?: string[], options?: { 780 | cwd?: string; 781 | input?: string|Buffer; 782 | stdio?: any; 783 | env?: any; 784 | uid?: number; 785 | gid?: number; 786 | timeout?: number; 787 | maxBuffer?: number; 788 | killSignal?: string; 789 | encoding?: string; 790 | }): ChildProcess; 791 | } 792 | 793 | declare module "url" { 794 | export interface Url { 795 | href: string; 796 | protocol: string; 797 | auth: string; 798 | hostname: string; 799 | port: string; 800 | host: string; 801 | pathname: string; 802 | search: string; 803 | query: any; // string | Object 804 | slashes: boolean; 805 | hash?: string; 806 | path?: string; 807 | } 808 | 809 | export interface UrlOptions { 810 | protocol?: string; 811 | auth?: string; 812 | hostname?: string; 813 | port?: string; 814 | host?: string; 815 | pathname?: string; 816 | search?: string; 817 | query?: any; 818 | hash?: string; 819 | path?: string; 820 | } 821 | 822 | export function parse(urlStr: string, parseQueryString?: boolean , slashesDenoteHost?: boolean ): Url; 823 | export function format(url: UrlOptions): string; 824 | export function resolve(from: string, to: string): string; 825 | } 826 | 827 | declare module "dns" { 828 | export function lookup(domain: string, family: number, callback: (err: Error, address: string, family: number) =>void ): string; 829 | export function lookup(domain: string, callback: (err: Error, address: string, family: number) =>void ): string; 830 | export function resolve(domain: string, rrtype: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 831 | export function resolve(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 832 | export function resolve4(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 833 | export function resolve6(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 834 | export function resolveMx(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 835 | export function resolveTxt(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 836 | export function resolveSrv(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 837 | export function resolveNs(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 838 | export function resolveCname(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; 839 | export function reverse(ip: string, callback: (err: Error, domains: string[]) =>void ): string[]; 840 | } 841 | 842 | declare module "net" { 843 | import stream = require("stream"); 844 | 845 | export interface Socket extends stream.Duplex { 846 | // Extended base methods 847 | write(buffer: Buffer): boolean; 848 | write(buffer: Buffer, cb?: Function): boolean; 849 | write(str: string, cb?: Function): boolean; 850 | write(str: string, encoding?: string, cb?: Function): boolean; 851 | write(str: string, encoding?: string, fd?: string): boolean; 852 | 853 | connect(port: number, host?: string, connectionListener?: Function): void; 854 | connect(path: string, connectionListener?: Function): void; 855 | bufferSize: number; 856 | setEncoding(encoding?: string): void; 857 | write(data: any, encoding?: string, callback?: Function): void; 858 | destroy(): void; 859 | pause(): void; 860 | resume(): void; 861 | setTimeout(timeout: number, callback?: Function): void; 862 | setNoDelay(noDelay?: boolean): void; 863 | setKeepAlive(enable?: boolean, initialDelay?: number): void; 864 | address(): { port: number; family: string; address: string; }; 865 | unref(): void; 866 | ref(): void; 867 | 868 | remoteAddress: string; 869 | remoteFamily: string; 870 | remotePort: number; 871 | localAddress: string; 872 | localPort: number; 873 | bytesRead: number; 874 | bytesWritten: number; 875 | 876 | // Extended base methods 877 | end(): void; 878 | end(buffer: Buffer, cb?: Function): void; 879 | end(str: string, cb?: Function): void; 880 | end(str: string, encoding?: string, cb?: Function): void; 881 | end(data?: any, encoding?: string): void; 882 | } 883 | 884 | export var Socket: { 885 | new (options?: { fd?: string; type?: string; allowHalfOpen?: boolean; }): Socket; 886 | }; 887 | 888 | export interface Server extends Socket { 889 | listen(port: number, host?: string, backlog?: number, listeningListener?: Function): Server; 890 | listen(path: string, listeningListener?: Function): Server; 891 | listen(handle: any, listeningListener?: Function): Server; 892 | close(callback?: Function): Server; 893 | address(): { port: number; family: string; address: string; }; 894 | maxConnections: number; 895 | connections: number; 896 | } 897 | export function createServer(connectionListener?: (socket: Socket) =>void ): Server; 898 | export function createServer(options?: { allowHalfOpen?: boolean; }, connectionListener?: (socket: Socket) =>void ): Server; 899 | export function connect(options: { allowHalfOpen?: boolean; }, connectionListener?: Function): Socket; 900 | export function connect(port: number, host?: string, connectionListener?: Function): Socket; 901 | export function connect(path: string, connectionListener?: Function): Socket; 902 | export function createConnection(options: { allowHalfOpen?: boolean; }, connectionListener?: Function): Socket; 903 | export function createConnection(port: number, host?: string, connectionListener?: Function): Socket; 904 | export function createConnection(path: string, connectionListener?: Function): Socket; 905 | export function isIP(input: string): number; 906 | export function isIPv4(input: string): boolean; 907 | export function isIPv6(input: string): boolean; 908 | } 909 | 910 | declare module "dgram" { 911 | import events = require("events"); 912 | 913 | interface RemoteInfo { 914 | address: string; 915 | port: number; 916 | size: number; 917 | } 918 | 919 | interface AddressInfo { 920 | address: string; 921 | family: string; 922 | port: number; 923 | } 924 | 925 | export function createSocket(type: string, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket; 926 | 927 | interface Socket extends events.EventEmitter { 928 | send(buf: Buffer, offset: number, length: number, port: number, address: string, callback?: (error: Error, bytes: number) => void): void; 929 | bind(port: number, address?: string, callback?: () => void): void; 930 | close(): void; 931 | address(): AddressInfo; 932 | setBroadcast(flag: boolean): void; 933 | setMulticastTTL(ttl: number): void; 934 | setMulticastLoopback(flag: boolean): void; 935 | addMembership(multicastAddress: string, multicastInterface?: string): void; 936 | dropMembership(multicastAddress: string, multicastInterface?: string): void; 937 | } 938 | } 939 | 940 | declare module "fs" { 941 | import stream = require("stream"); 942 | import events = require("events"); 943 | 944 | interface Stats { 945 | isFile(): boolean; 946 | isDirectory(): boolean; 947 | isBlockDevice(): boolean; 948 | isCharacterDevice(): boolean; 949 | isSymbolicLink(): boolean; 950 | isFIFO(): boolean; 951 | isSocket(): boolean; 952 | dev: number; 953 | ino: number; 954 | mode: number; 955 | nlink: number; 956 | uid: number; 957 | gid: number; 958 | rdev: number; 959 | size: number; 960 | blksize: number; 961 | blocks: number; 962 | atime: Date; 963 | mtime: Date; 964 | ctime: Date; 965 | } 966 | 967 | interface FSWatcher extends events.EventEmitter { 968 | close(): void; 969 | } 970 | 971 | export interface ReadStream extends stream.Readable { 972 | close(): void; 973 | } 974 | export interface WriteStream extends stream.Writable { 975 | close(): void; 976 | } 977 | 978 | export function rename(oldPath: string, newPath: string, callback?: (err?: NodeJS.ErrnoException) => void): void; 979 | export function renameSync(oldPath: string, newPath: string): void; 980 | export function truncate(path: string, callback?: (err?: NodeJS.ErrnoException) => void): void; 981 | export function truncate(path: string, len: number, callback?: (err?: NodeJS.ErrnoException) => void): void; 982 | export function truncateSync(path: string, len?: number): void; 983 | export function ftruncate(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void; 984 | export function ftruncate(fd: number, len: number, callback?: (err?: NodeJS.ErrnoException) => void): void; 985 | export function ftruncateSync(fd: number, len?: number): void; 986 | export function chown(path: string, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void; 987 | export function chownSync(path: string, uid: number, gid: number): void; 988 | export function fchown(fd: number, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void; 989 | export function fchownSync(fd: number, uid: number, gid: number): void; 990 | export function lchown(path: string, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void; 991 | export function lchownSync(path: string, uid: number, gid: number): void; 992 | export function chmod(path: string, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; 993 | export function chmod(path: string, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; 994 | export function chmodSync(path: string, mode: number): void; 995 | export function chmodSync(path: string, mode: string): void; 996 | export function fchmod(fd: number, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; 997 | export function fchmod(fd: number, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; 998 | export function fchmodSync(fd: number, mode: number): void; 999 | export function fchmodSync(fd: number, mode: string): void; 1000 | export function lchmod(path: string, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; 1001 | export function lchmod(path: string, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; 1002 | export function lchmodSync(path: string, mode: number): void; 1003 | export function lchmodSync(path: string, mode: string): void; 1004 | export function stat(path: string, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void; 1005 | export function lstat(path: string, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void; 1006 | export function fstat(fd: number, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void; 1007 | export function statSync(path: string): Stats; 1008 | export function lstatSync(path: string): Stats; 1009 | export function fstatSync(fd: number): Stats; 1010 | export function link(srcpath: string, dstpath: string, callback?: (err?: NodeJS.ErrnoException) => void): void; 1011 | export function linkSync(srcpath: string, dstpath: string): void; 1012 | export function symlink(srcpath: string, dstpath: string, type?: string, callback?: (err?: NodeJS.ErrnoException) => void): void; 1013 | export function symlinkSync(srcpath: string, dstpath: string, type?: string): void; 1014 | export function readlink(path: string, callback?: (err: NodeJS.ErrnoException, linkString: string) => any): void; 1015 | export function readlinkSync(path: string): string; 1016 | export function realpath(path: string, callback?: (err: NodeJS.ErrnoException, resolvedPath: string) => any): void; 1017 | export function realpath(path: string, cache: {[path: string]: string}, callback: (err: NodeJS.ErrnoException, resolvedPath: string) =>any): void; 1018 | export function realpathSync(path: string, cache?: {[path: string]: string}): string; 1019 | export function unlink(path: string, callback?: (err?: NodeJS.ErrnoException) => void): void; 1020 | export function unlinkSync(path: string): void; 1021 | export function rmdir(path: string, callback?: (err?: NodeJS.ErrnoException) => void): void; 1022 | export function rmdirSync(path: string): void; 1023 | export function mkdir(path: string, callback?: (err?: NodeJS.ErrnoException) => void): void; 1024 | export function mkdir(path: string, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; 1025 | export function mkdir(path: string, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; 1026 | export function mkdirSync(path: string, mode?: number): void; 1027 | export function mkdirSync(path: string, mode?: string): void; 1028 | export function readdir(path: string, callback?: (err: NodeJS.ErrnoException, files: string[]) => void): void; 1029 | export function readdirSync(path: string): string[]; 1030 | export function close(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void; 1031 | export function closeSync(fd: number): void; 1032 | export function open(path: string, flags: string, callback?: (err: NodeJS.ErrnoException, fd: number) => any): void; 1033 | export function open(path: string, flags: string, mode: number, callback?: (err: NodeJS.ErrnoException, fd: number) => any): void; 1034 | export function open(path: string, flags: string, mode: string, callback?: (err: NodeJS.ErrnoException, fd: number) => any): void; 1035 | export function openSync(path: string, flags: string, mode?: number): number; 1036 | export function openSync(path: string, flags: string, mode?: string): number; 1037 | export function utimes(path: string, atime: number, mtime: number, callback?: (err?: NodeJS.ErrnoException) => void): void; 1038 | export function utimes(path: string, atime: Date, mtime: Date, callback?: (err?: NodeJS.ErrnoException) => void): void; 1039 | export function utimesSync(path: string, atime: number, mtime: number): void; 1040 | export function utimesSync(path: string, atime: Date, mtime: Date): void; 1041 | export function futimes(fd: number, atime: number, mtime: number, callback?: (err?: NodeJS.ErrnoException) => void): void; 1042 | export function futimes(fd: number, atime: Date, mtime: Date, callback?: (err?: NodeJS.ErrnoException) => void): void; 1043 | export function futimesSync(fd: number, atime: number, mtime: number): void; 1044 | export function futimesSync(fd: number, atime: Date, mtime: Date): void; 1045 | export function fsync(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void; 1046 | export function fsyncSync(fd: number): void; 1047 | export function write(fd: number, buffer: Buffer, offset: number, length: number, position: number, callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void; 1048 | export function writeSync(fd: number, buffer: Buffer, offset: number, length: number, position: number): number; 1049 | export function read(fd: number, buffer: Buffer, offset: number, length: number, position: number, callback?: (err: NodeJS.ErrnoException, bytesRead: number, buffer: Buffer) => void): void; 1050 | export function readSync(fd: number, buffer: Buffer, offset: number, length: number, position: number): number; 1051 | export function readFile(filename: string, encoding: string, callback: (err: NodeJS.ErrnoException, data: string) => void): void; 1052 | export function readFile(filename: string, options: { encoding: string; flag?: string; }, callback: (err: NodeJS.ErrnoException, data: string) => void): void; 1053 | export function readFile(filename: string, options: { flag?: string; }, callback: (err: NodeJS.ErrnoException, data: Buffer) => void): void; 1054 | export function readFile(filename: string, callback: (err: NodeJS.ErrnoException, data: Buffer) => void ): void; 1055 | export function readFileSync(filename: string, encoding: string): string; 1056 | export function readFileSync(filename: string, options: { encoding: string; flag?: string; }): string; 1057 | export function readFileSync(filename: string, options?: { flag?: string; }): Buffer; 1058 | export function writeFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void; 1059 | export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; 1060 | export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; 1061 | export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; 1062 | export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void; 1063 | export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; 1064 | export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; 1065 | export function appendFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void; 1066 | export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; 1067 | export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void; 1068 | export function watchFile(filename: string, listener: (curr: Stats, prev: Stats) => void): void; 1069 | export function watchFile(filename: string, options: { persistent?: boolean; interval?: number; }, listener: (curr: Stats, prev: Stats) => void): void; 1070 | export function unwatchFile(filename: string, listener?: (curr: Stats, prev: Stats) => void): void; 1071 | export function watch(filename: string, listener?: (event: string, filename: string) => any): FSWatcher; 1072 | export function watch(filename: string, options: { persistent?: boolean; }, listener?: (event: string, filename: string) => any): FSWatcher; 1073 | export function exists(path: string, callback?: (exists: boolean) => void): void; 1074 | export function existsSync(path: string): boolean; 1075 | export function createReadStream(path: string, options?: { 1076 | flags?: string; 1077 | encoding?: string; 1078 | fd?: string; 1079 | mode?: number; 1080 | bufferSize?: number; 1081 | }): ReadStream; 1082 | export function createReadStream(path: string, options?: { 1083 | flags?: string; 1084 | encoding?: string; 1085 | fd?: string; 1086 | mode?: string; 1087 | bufferSize?: number; 1088 | }): ReadStream; 1089 | export function createWriteStream(path: string, options?: { 1090 | flags?: string; 1091 | encoding?: string; 1092 | string?: string; 1093 | }): WriteStream; 1094 | } 1095 | 1096 | declare module "path" { 1097 | 1098 | export interface ParsedPath { 1099 | root: string; 1100 | dir: string; 1101 | base: string; 1102 | ext: string; 1103 | name: string; 1104 | } 1105 | 1106 | export function normalize(p: string): string; 1107 | export function join(...paths: any[]): string; 1108 | export function resolve(...pathSegments: any[]): string; 1109 | export function isAbsolute(p: string): boolean; 1110 | export function relative(from: string, to: string): string; 1111 | export function dirname(p: string): string; 1112 | export function basename(p: string, ext?: string): string; 1113 | export function extname(p: string): string; 1114 | export var sep: string; 1115 | export var delimiter: string; 1116 | export function parse(p: string): ParsedPath; 1117 | export function format(pP: ParsedPath): string; 1118 | 1119 | export module posix { 1120 | export function normalize(p: string): string; 1121 | export function join(...paths: any[]): string; 1122 | export function resolve(...pathSegments: any[]): string; 1123 | export function isAbsolute(p: string): boolean; 1124 | export function relative(from: string, to: string): string; 1125 | export function dirname(p: string): string; 1126 | export function basename(p: string, ext?: string): string; 1127 | export function extname(p: string): string; 1128 | export var sep: string; 1129 | export var delimiter: string; 1130 | export function parse(p: string): ParsedPath; 1131 | export function format(pP: ParsedPath): string; 1132 | } 1133 | 1134 | export module win32 { 1135 | export function normalize(p: string): string; 1136 | export function join(...paths: any[]): string; 1137 | export function resolve(...pathSegments: any[]): string; 1138 | export function isAbsolute(p: string): boolean; 1139 | export function relative(from: string, to: string): string; 1140 | export function dirname(p: string): string; 1141 | export function basename(p: string, ext?: string): string; 1142 | export function extname(p: string): string; 1143 | export var sep: string; 1144 | export var delimiter: string; 1145 | export function parse(p: string): ParsedPath; 1146 | export function format(pP: ParsedPath): string; 1147 | } 1148 | } 1149 | 1150 | declare module "string_decoder" { 1151 | export interface NodeStringDecoder { 1152 | write(buffer: Buffer): string; 1153 | detectIncompleteChar(buffer: Buffer): number; 1154 | } 1155 | export var StringDecoder: { 1156 | new (encoding: string): NodeStringDecoder; 1157 | }; 1158 | } 1159 | 1160 | declare module "tls" { 1161 | import crypto = require("crypto"); 1162 | import net = require("net"); 1163 | import stream = require("stream"); 1164 | 1165 | var CLIENT_RENEG_LIMIT: number; 1166 | var CLIENT_RENEG_WINDOW: number; 1167 | 1168 | export interface TlsOptions { 1169 | pfx?: any; //string or buffer 1170 | key?: any; //string or buffer 1171 | passphrase?: string; 1172 | cert?: any; 1173 | ca?: any; //string or buffer 1174 | crl?: any; //string or string array 1175 | ciphers?: string; 1176 | honorCipherOrder?: any; 1177 | requestCert?: boolean; 1178 | rejectUnauthorized?: boolean; 1179 | NPNProtocols?: any; //array or Buffer; 1180 | SNICallback?: (servername: string) => any; 1181 | } 1182 | 1183 | export interface ConnectionOptions { 1184 | host?: string; 1185 | port?: number; 1186 | socket?: net.Socket; 1187 | pfx?: any; //string | Buffer 1188 | key?: any; //string | Buffer 1189 | passphrase?: string; 1190 | cert?: any; //string | Buffer 1191 | ca?: any; //Array of string | Buffer 1192 | rejectUnauthorized?: boolean; 1193 | NPNProtocols?: any; //Array of string | Buffer 1194 | servername?: string; 1195 | } 1196 | 1197 | export interface Server extends net.Server { 1198 | // Extended base methods 1199 | listen(port: number, host?: string, backlog?: number, listeningListener?: Function): Server; 1200 | listen(path: string, listeningListener?: Function): Server; 1201 | listen(handle: any, listeningListener?: Function): Server; 1202 | 1203 | listen(port: number, host?: string, callback?: Function): Server; 1204 | close(): Server; 1205 | address(): { port: number; family: string; address: string; }; 1206 | addContext(hostName: string, credentials: { 1207 | key: string; 1208 | cert: string; 1209 | ca: string; 1210 | }): void; 1211 | maxConnections: number; 1212 | connections: number; 1213 | } 1214 | 1215 | export interface ClearTextStream extends stream.Duplex { 1216 | authorized: boolean; 1217 | authorizationError: Error; 1218 | getPeerCertificate(): any; 1219 | getCipher: { 1220 | name: string; 1221 | version: string; 1222 | }; 1223 | address: { 1224 | port: number; 1225 | family: string; 1226 | address: string; 1227 | }; 1228 | remoteAddress: string; 1229 | remotePort: number; 1230 | } 1231 | 1232 | export interface SecurePair { 1233 | encrypted: any; 1234 | cleartext: any; 1235 | } 1236 | 1237 | export function createServer(options: TlsOptions, secureConnectionListener?: (cleartextStream: ClearTextStream) =>void ): Server; 1238 | export function connect(options: TlsOptions, secureConnectionListener?: () =>void ): ClearTextStream; 1239 | export function connect(port: number, host?: string, options?: ConnectionOptions, secureConnectListener?: () =>void ): ClearTextStream; 1240 | export function connect(port: number, options?: ConnectionOptions, secureConnectListener?: () =>void ): ClearTextStream; 1241 | export function createSecurePair(credentials?: crypto.Credentials, isServer?: boolean, requestCert?: boolean, rejectUnauthorized?: boolean): SecurePair; 1242 | } 1243 | 1244 | declare module "crypto" { 1245 | export interface CredentialDetails { 1246 | pfx: string; 1247 | key: string; 1248 | passphrase: string; 1249 | cert: string; 1250 | ca: any; //string | string array 1251 | crl: any; //string | string array 1252 | ciphers: string; 1253 | } 1254 | export interface Credentials { context?: any; } 1255 | export function createCredentials(details: CredentialDetails): Credentials; 1256 | export function createHash(algorithm: string): Hash; 1257 | export function createHmac(algorithm: string, key: string): Hmac; 1258 | export function createHmac(algorithm: string, key: Buffer): Hmac; 1259 | interface Hash { 1260 | update(data: any, input_encoding?: string): Hash; 1261 | digest(encoding: 'buffer'): Buffer; 1262 | digest(encoding: string): any; 1263 | digest(): Buffer; 1264 | } 1265 | interface Hmac { 1266 | update(data: any, input_encoding?: string): Hmac; 1267 | digest(encoding: 'buffer'): Buffer; 1268 | digest(encoding: string): any; 1269 | digest(): Buffer; 1270 | } 1271 | export function createCipher(algorithm: string, password: any): Cipher; 1272 | export function createCipheriv(algorithm: string, key: any, iv: any): Cipher; 1273 | interface Cipher { 1274 | update(data: Buffer): Buffer; 1275 | update(data: string, input_encoding?: string, output_encoding?: string): string; 1276 | final(): Buffer; 1277 | final(output_encoding: string): string; 1278 | setAutoPadding(auto_padding: boolean): void; 1279 | } 1280 | export function createDecipher(algorithm: string, password: any): Decipher; 1281 | export function createDecipheriv(algorithm: string, key: any, iv: any): Decipher; 1282 | interface Decipher { 1283 | update(data: Buffer): Buffer; 1284 | update(data: string, input_encoding?: string, output_encoding?: string): string; 1285 | final(): Buffer; 1286 | final(output_encoding: string): string; 1287 | setAutoPadding(auto_padding: boolean): void; 1288 | } 1289 | export function createSign(algorithm: string): Signer; 1290 | interface Signer { 1291 | update(data: any): void; 1292 | sign(private_key: string, output_format: string): string; 1293 | } 1294 | export function createVerify(algorith: string): Verify; 1295 | interface Verify { 1296 | update(data: any): void; 1297 | verify(object: string, signature: string, signature_format?: string): boolean; 1298 | } 1299 | export function createDiffieHellman(prime_length: number): DiffieHellman; 1300 | export function createDiffieHellman(prime: number, encoding?: string): DiffieHellman; 1301 | interface DiffieHellman { 1302 | generateKeys(encoding?: string): string; 1303 | computeSecret(other_public_key: string, input_encoding?: string, output_encoding?: string): string; 1304 | getPrime(encoding?: string): string; 1305 | getGenerator(encoding: string): string; 1306 | getPublicKey(encoding?: string): string; 1307 | getPrivateKey(encoding?: string): string; 1308 | setPublicKey(public_key: string, encoding?: string): void; 1309 | setPrivateKey(public_key: string, encoding?: string): void; 1310 | } 1311 | export function getDiffieHellman(group_name: string): DiffieHellman; 1312 | export function pbkdf2(password: string, salt: string, iterations: number, keylen: number, callback: (err: Error, derivedKey: Buffer) => any): void; 1313 | export function pbkdf2Sync(password: string, salt: string, iterations: number, keylen: number) : Buffer; 1314 | export function randomBytes(size: number): Buffer; 1315 | export function randomBytes(size: number, callback: (err: Error, buf: Buffer) =>void ): void; 1316 | export function pseudoRandomBytes(size: number): Buffer; 1317 | export function pseudoRandomBytes(size: number, callback: (err: Error, buf: Buffer) =>void ): void; 1318 | } 1319 | 1320 | declare module "stream" { 1321 | import events = require("events"); 1322 | 1323 | export interface Stream extends events.EventEmitter { 1324 | pipe(destination: T, options?: { end?: boolean; }): T; 1325 | } 1326 | 1327 | export interface ReadableOptions { 1328 | highWaterMark?: number; 1329 | encoding?: string; 1330 | objectMode?: boolean; 1331 | } 1332 | 1333 | export class Readable extends events.EventEmitter implements NodeJS.ReadableStream { 1334 | readable: boolean; 1335 | constructor(opts?: ReadableOptions); 1336 | _read(size: number): void; 1337 | read(size?: number): string|Buffer; 1338 | setEncoding(encoding: string): void; 1339 | pause(): void; 1340 | resume(): void; 1341 | pipe(destination: T, options?: { end?: boolean; }): T; 1342 | unpipe(destination?: T): void; 1343 | unshift(chunk: string): void; 1344 | unshift(chunk: Buffer): void; 1345 | wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream; 1346 | push(chunk: any, encoding?: string): boolean; 1347 | } 1348 | 1349 | export interface WritableOptions { 1350 | highWaterMark?: number; 1351 | decodeStrings?: boolean; 1352 | } 1353 | 1354 | export class Writable extends events.EventEmitter implements NodeJS.WritableStream { 1355 | writable: boolean; 1356 | constructor(opts?: WritableOptions); 1357 | _write(data: Buffer, encoding: string, callback: Function): void; 1358 | _write(data: string, encoding: string, callback: Function): void; 1359 | write(buffer: Buffer, cb?: Function): boolean; 1360 | write(str: string, cb?: Function): boolean; 1361 | write(str: string, encoding?: string, cb?: Function): boolean; 1362 | end(): void; 1363 | end(buffer: Buffer, cb?: Function): void; 1364 | end(str: string, cb?: Function): void; 1365 | end(str: string, encoding?: string, cb?: Function): void; 1366 | } 1367 | 1368 | export interface DuplexOptions extends ReadableOptions, WritableOptions { 1369 | allowHalfOpen?: boolean; 1370 | } 1371 | 1372 | // Note: Duplex extends both Readable and Writable. 1373 | export class Duplex extends Readable implements NodeJS.ReadWriteStream { 1374 | writable: boolean; 1375 | constructor(opts?: DuplexOptions); 1376 | _write(data: Buffer, encoding: string, callback: Function): void; 1377 | _write(data: string, encoding: string, callback: Function): void; 1378 | write(buffer: Buffer, cb?: Function): boolean; 1379 | write(str: string, cb?: Function): boolean; 1380 | write(str: string, encoding?: string, cb?: Function): boolean; 1381 | end(): void; 1382 | end(buffer: Buffer, cb?: Function): void; 1383 | end(str: string, cb?: Function): void; 1384 | end(str: string, encoding?: string, cb?: Function): void; 1385 | } 1386 | 1387 | export interface TransformOptions extends ReadableOptions, WritableOptions {} 1388 | 1389 | // Note: Transform lacks the _read and _write methods of Readable/Writable. 1390 | export class Transform extends events.EventEmitter implements NodeJS.ReadWriteStream { 1391 | readable: boolean; 1392 | writable: boolean; 1393 | constructor(opts?: TransformOptions); 1394 | _transform(chunk: Buffer, encoding: string, callback: Function): void; 1395 | _transform(chunk: string, encoding: string, callback: Function): void; 1396 | _flush(callback: Function): void; 1397 | read(size?: number): any; 1398 | setEncoding(encoding: string): void; 1399 | pause(): void; 1400 | resume(): void; 1401 | pipe(destination: T, options?: { end?: boolean; }): T; 1402 | unpipe(destination?: T): void; 1403 | unshift(chunk: string): void; 1404 | unshift(chunk: Buffer): void; 1405 | wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream; 1406 | push(chunk: any, encoding?: string): boolean; 1407 | write(buffer: Buffer, cb?: Function): boolean; 1408 | write(str: string, cb?: Function): boolean; 1409 | write(str: string, encoding?: string, cb?: Function): boolean; 1410 | end(): void; 1411 | end(buffer: Buffer, cb?: Function): void; 1412 | end(str: string, cb?: Function): void; 1413 | end(str: string, encoding?: string, cb?: Function): void; 1414 | } 1415 | 1416 | export class PassThrough extends Transform {} 1417 | } 1418 | 1419 | declare module "util" { 1420 | export interface InspectOptions { 1421 | showHidden?: boolean; 1422 | depth?: number; 1423 | colors?: boolean; 1424 | customInspect?: boolean; 1425 | } 1426 | 1427 | export function format(format: any, ...param: any[]): string; 1428 | export function debug(string: string): void; 1429 | export function error(...param: any[]): void; 1430 | export function puts(...param: any[]): void; 1431 | export function print(...param: any[]): void; 1432 | export function log(string: string): void; 1433 | export function inspect(object: any, showHidden?: boolean, depth?: number, color?: boolean): string; 1434 | export function inspect(object: any, options: InspectOptions): string; 1435 | export function isArray(object: any): boolean; 1436 | export function isRegExp(object: any): boolean; 1437 | export function isDate(object: any): boolean; 1438 | export function isError(object: any): boolean; 1439 | export function inherits(constructor: any, superConstructor: any): void; 1440 | } 1441 | 1442 | declare module "assert" { 1443 | function internal (value: any, message?: string): void; 1444 | module internal { 1445 | export class AssertionError implements Error { 1446 | name: string; 1447 | message: string; 1448 | actual: any; 1449 | expected: any; 1450 | operator: string; 1451 | generatedMessage: boolean; 1452 | 1453 | constructor(options?: {message?: string; actual?: any; expected?: any; 1454 | operator?: string; stackStartFunction?: Function}); 1455 | } 1456 | 1457 | export function fail(actual?: any, expected?: any, message?: string, operator?: string): void; 1458 | export function ok(value: any, message?: string): void; 1459 | export function equal(actual: any, expected: any, message?: string): void; 1460 | export function notEqual(actual: any, expected: any, message?: string): void; 1461 | export function deepEqual(actual: any, expected: any, message?: string): void; 1462 | export function notDeepEqual(acutal: any, expected: any, message?: string): void; 1463 | export function strictEqual(actual: any, expected: any, message?: string): void; 1464 | export function notStrictEqual(actual: any, expected: any, message?: string): void; 1465 | export var throws: { 1466 | (block: Function, message?: string): void; 1467 | (block: Function, error: Function, message?: string): void; 1468 | (block: Function, error: RegExp, message?: string): void; 1469 | (block: Function, error: (err: any) => boolean, message?: string): void; 1470 | }; 1471 | 1472 | export var doesNotThrow: { 1473 | (block: Function, message?: string): void; 1474 | (block: Function, error: Function, message?: string): void; 1475 | (block: Function, error: RegExp, message?: string): void; 1476 | (block: Function, error: (err: any) => boolean, message?: string): void; 1477 | }; 1478 | 1479 | export function ifError(value: any): void; 1480 | } 1481 | 1482 | export = internal; 1483 | } 1484 | 1485 | declare module "tty" { 1486 | import net = require("net"); 1487 | 1488 | export function isatty(fd: number): boolean; 1489 | export interface ReadStream extends net.Socket { 1490 | isRaw: boolean; 1491 | setRawMode(mode: boolean): void; 1492 | } 1493 | export interface WriteStream extends net.Socket { 1494 | columns: number; 1495 | rows: number; 1496 | } 1497 | } 1498 | 1499 | declare module "domain" { 1500 | import events = require("events"); 1501 | 1502 | export class Domain extends events.EventEmitter { 1503 | run(fn: Function): void; 1504 | add(emitter: events.EventEmitter): void; 1505 | remove(emitter: events.EventEmitter): void; 1506 | bind(cb: (err: Error, data: any) => any): any; 1507 | intercept(cb: (data: any) => any): any; 1508 | dispose(): void; 1509 | 1510 | addListener(event: string, listener: Function): Domain; 1511 | on(event: string, listener: Function): Domain; 1512 | once(event: string, listener: Function): Domain; 1513 | removeListener(event: string, listener: Function): Domain; 1514 | removeAllListeners(event?: string): Domain; 1515 | } 1516 | 1517 | export function create(): Domain; 1518 | } 1519 | -------------------------------------------------------------------------------- /typings/q-io/Q-io.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Q-io 2 | // Project: https://github.com/kriskowal/q-io 3 | // Definitions by: Bart van der Schoor 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | /// 8 | 9 | //TODO add support for q-io/http-apps 10 | //TODO add verified support for q-io/fs-mock 11 | //TODO fix Readers/Writers properly 12 | //TODO find solution for overloaded return types (QioFS.open/QioFS.read) 13 | // for some ideas see https://typescript.codeplex.com/discussions/461587#post1105930 14 | 15 | declare module QioFS { 16 | 17 | //TODO how to define the multiple return types? use any for now? 18 | export function open(path:string, options?:any):Q.Promise; 19 | //export function open(path:string, options?:any):Q.Promise; 20 | //export function open(path:string, options?:any):Q.Promise; 21 | //export function open(path:string, options?:any):Q.Promise; 22 | 23 | //TODO how to define the multiple return types? use any for now? 24 | export function read(path:string, options?:any):Q.Promise; 25 | //export function read(path:string, options?:any):Q.Promise; 26 | //export function read(path:string, options?:any):Q.Promise; 27 | 28 | export function write(path:string, content:Buffer, options?:any):Q.Promise; 29 | export function write(path:string, content:string, options?:any):Q.Promise; 30 | 31 | export function append(path:string, content:Buffer, options?:any):Q.Promise; 32 | export function append(path:string, content:string, options?:any):Q.Promise; 33 | 34 | export function copy(source:string, target:string):Q.Promise; 35 | export function copyTree(source:string, target:string):Q.Promise; 36 | 37 | export function list(path:string):Q.Promise; 38 | export function listTree(path:string, guard?:(path:string, stat:any) => boolean):Q.Promise; 39 | export function listDirectoryTree(path:string):Q.Promise; 40 | 41 | export function makeDirectory(path:string, mode?:string):Q.Promise; 42 | export function makeDirectory(path:string, mode?:number):Q.Promise; 43 | export function makeTree(path:string, mode?:string):Q.Promise; 44 | export function makeTree(path:string, mode?:number):Q.Promise; 45 | 46 | export function remove(path:string):Q.Promise; 47 | export function removeTree(path:string):Q.Promise; 48 | 49 | export function rename(source:string, target:string):Q.Promise; 50 | export function move(source:string, target:string):Q.Promise; 51 | 52 | export function link(source:string, target:any):Q.Promise; 53 | 54 | export function symbolicCopy(source:string, target:string, type:string):Q.Promise; 55 | export function symbolicLink(target:string, link:string, type:string):Q.Promise; 56 | 57 | export function chown(path:string, uid:number, gid:number):Q.Promise; 58 | export function chmod(path:string, mode?:string):Q.Promise; 59 | export function chmod(path:string, mode?:number):Q.Promise; 60 | 61 | export function stat(path:string):Q.Promise; 62 | export function statLink(path:string):Q.Promise; 63 | export function statFd(fd:number):Q.Promise; 64 | 65 | export function exists(path:string):Q.Promise; 66 | 67 | export function isFile(path:string):Q.Promise; 68 | export function isDirectory(path:string):Q.Promise; 69 | export function isSymbolicLink(path:string):Q.Promise; 70 | 71 | export function lastModified(path:string):Q.Promise; 72 | export function lastAccessed(path:string):Q.Promise; 73 | 74 | export function split(path:string):string[]; 75 | export function join(...paths:string[]):string; 76 | export function join(paths:string[]):string; 77 | export function resolve(...path:string[]):string; 78 | export function resolve(paths:string[]):string; 79 | export function normal(...path:string[]):string; 80 | export function normal(paths:string[]):string; 81 | export function absolute(path:string):string; 82 | 83 | export function canonical(path:string):Q.Promise; 84 | export function readLink(path:string):Q.Promise; 85 | 86 | export function contains(parent:string, child:string):boolean; 87 | 88 | export function relative(source:string, target:string):Q.Promise; 89 | 90 | export function relativeFromFile(source:string, target:string):string; 91 | export function relativeFromDirectory(source:string, target:string):string; 92 | 93 | export function isAbsolute(path:string):boolean; 94 | export function isRelative(path:string):boolean; 95 | export function isRoot(path:string):boolean; 96 | 97 | export function root(path:string):string; 98 | export function directory(path:string):string; 99 | export function base(path:string, extension:string):string; 100 | export function extension(path:string):string; 101 | 102 | //this should return a q-io/fs-mock MockFS 103 | export function reroot(path:string):typeof QioFS; 104 | 105 | export function toObject(path:string):{[path:string]:Buffer}; 106 | 107 | //listed but not implemented by Q-io 108 | //export function glob(pattern):Q.Promise; 109 | //export function match(pattern, path:string):Q.Promise; 110 | 111 | //TODO link this to node.js FS module (no lazy clones) 112 | interface Stats { 113 | node:NodeStats; 114 | size:number; 115 | } 116 | interface NodeStats { 117 | isFile():boolean; 118 | isDirectory():boolean; 119 | isBlockDevice():boolean; 120 | isCharacterDevice():boolean; 121 | isSymbolicLink():boolean; 122 | isFIFO():boolean; 123 | isSocket():boolean; 124 | node:NodeStats; 125 | dev:number; 126 | ino:number; 127 | mode:number; 128 | nlink:number; 129 | uid:number; 130 | gid:number; 131 | rdev:number; 132 | size:number; 133 | blksize:number; 134 | blocks:number; 135 | atime:Date; 136 | mtime:Date; 137 | ctime:Date; 138 | } 139 | } 140 | 141 | declare module QioHTTP { 142 | export function request(request:Request):Q.Promise; 143 | export function request(url:string):Q.Promise; 144 | 145 | export function read(request:Request):Q.Promise; 146 | export function read(url:string):Q.Promise; 147 | 148 | export function normalizeRequest(request:Request):Request; 149 | export function normalizeRequest(url:string):Request; 150 | export function normalizeResponse(response:Response):Response; 151 | 152 | interface Request { 153 | url:string; 154 | path:string; 155 | scriptName:string; 156 | pathInfo:string; 157 | version:string[]; 158 | method:string; 159 | scheme:string; 160 | 161 | host:string; 162 | port:number; 163 | remoteHost:string; 164 | remotePort:number; 165 | 166 | headers:Headers; 167 | agent:any; 168 | body:any; 169 | node:any; 170 | } 171 | interface Response { 172 | status:number; 173 | headers:Headers; 174 | body:Qio.Reader 175 | onclose:() => void; 176 | node:any; 177 | } 178 | interface Headers { 179 | [name:string]:any; 180 | // [name:string]:any[]; 181 | } 182 | interface Body extends Qio.Stream { 183 | 184 | } 185 | interface Application { 186 | (req:Request):Q.Promise; 187 | } 188 | } 189 | 190 | declare module Qio { 191 | interface ForEachCallback { 192 | (chunk:Buffer):Q.Promise; 193 | (chunk:string):Q.Promise; 194 | } 195 | interface ForEach { 196 | forEach(callback:ForEachCallback):Q.Promise; 197 | } 198 | 199 | interface Reader extends ForEach { 200 | read(charset:string):Q.Promise; 201 | read():Q.Promise; 202 | close():void; 203 | node: NodeJS.ReadableStream; 204 | } 205 | interface Writer { 206 | write(content:string):void; 207 | write(content:Buffer):void; 208 | flush():Q.Promise; 209 | close():void; 210 | destroy():void; 211 | node: NodeJS.WritableStream; 212 | } 213 | 214 | interface Stream { 215 | read(charset:string):Q.Promise; 216 | read():Q.Promise; 217 | write(content:string):void; 218 | write(content:Buffer):void; 219 | flush():Q.Promise; 220 | close():void; 221 | destroy():void; 222 | node:any; 223 | } 224 | 225 | interface BufferReader extends QioBufferReader { 226 | 227 | } 228 | } 229 | interface QioBufferReader { 230 | new ():Qio.Reader; 231 | read(stream:Qio.Reader, charset:string):string; 232 | read(stream:Qio.Reader):Buffer; 233 | join(buffers:Buffer[]):Buffer; 234 | } 235 | interface QioBufferWriter { 236 | (writer:Buffer):Qio.Writer; 237 | Writer:Qio.Writer; 238 | } 239 | interface QioBufferStream { 240 | (buffer:Buffer, encoding:string):Qio.Stream 241 | } 242 | 243 | declare module "q-io/http" { 244 | export = QioHTTP; 245 | } 246 | declare module "q-io/fs" { 247 | export = QioFS; 248 | } 249 | declare module "q-io/reader" { 250 | export = QioBufferReader; 251 | } 252 | declare module "q-io/writer" { 253 | export = QioBufferWriter; 254 | } 255 | declare module "q-io/buffer-stream" { 256 | export = QioBufferStream; 257 | } 258 | --------------------------------------------------------------------------------