├── .gitignore ├── .gitmodules ├── CHANGES.md ├── Makefile ├── README.md ├── assets ├── ajax_spinner.gif ├── bootstrap │ ├── css │ │ ├── bootstrap-responsive.css │ │ ├── bootstrap-responsive.min.css │ │ ├── bootstrap.css │ │ └── bootstrap.min.css │ ├── img │ │ ├── glyphicons-halflings-white.png │ │ └── glyphicons-halflings.png │ └── js │ │ ├── bootstrap.js │ │ └── bootstrap.min.js ├── css │ ├── docs.css │ └── sitewide.css ├── docs-agent-diagram.jpg ├── docs-grimwidget.png ├── docs-messaging-diagram.png ├── docs.js ├── favicon.png ├── hero-bg.jpg ├── icon-download.png ├── icon-idea.png ├── icon-link.png ├── icon-network.png ├── index.js ├── jquery-2.1.0.min.js ├── jquery.sticky.js ├── logo.png ├── marked.js ├── mdworker.js └── prism │ ├── prism.css │ └── prism.js ├── docs.html ├── docs └── en │ └── 0.6.2 │ ├── api │ ├── agent.md │ ├── bindrequestevents.md │ ├── bridgeserver.md │ ├── contenttypes.md │ ├── dispatch.md │ ├── eventemitter.md │ ├── eventhost.md │ ├── eventstream.md │ ├── httpheaders.md │ ├── pageserver.md │ ├── patchxhr.md │ ├── pipe.md │ ├── preferredtypes.md │ ├── promises.md │ ├── querylinks.md │ ├── relay.md │ ├── request.md │ ├── response.md │ ├── rtcbridgeserver.md │ ├── server.md │ ├── setdispatchwrapper.md │ ├── subscribe.md │ ├── uri_helpers.md │ ├── worker.md │ └── workerbridgeserver.md │ ├── example_mdviewer.md │ ├── hosts.md │ ├── httpl.md │ ├── linkheader.md │ ├── managing_servers.md │ ├── navscheme.md │ └── todosoa.md ├── examples ├── charcount.js ├── slugify.js └── toupper.js ├── index.html ├── local.js ├── local.min.js ├── package.json ├── scripts └── minify.sh ├── src ├── config.js ├── constants.js ├── index.js ├── promises.js ├── request-event.js ├── spawners.js ├── util │ ├── dom.js │ ├── event-emitter.js │ └── index.js ├── web │ ├── agent.js │ ├── bridge-server.js │ ├── content-types.js │ ├── dispatch.js │ ├── helpers.js │ ├── http-headers.js │ ├── httpl.js │ ├── relay.js │ ├── request.js │ ├── response.js │ ├── rtc-bridge-server.js │ ├── schemes.js │ ├── server.js │ ├── subscribe.js │ ├── uri-template.js │ └── worker-bridge-server.js └── worker │ ├── config.js │ ├── index.js │ └── page-bridge-server.js └── test ├── client.html ├── client └── browser.js ├── doctest ├── .gitignore ├── .gitmodules ├── .hgignore ├── .resources │ ├── CNAME │ ├── boilerplate │ │ ├── 404.html │ │ ├── css │ │ │ ├── main.css │ │ │ ├── normalize.css │ │ │ └── normalize.min.css │ │ ├── favicon.ico │ │ ├── index.html │ │ └── js │ │ │ ├── main.js │ │ │ └── vendor │ │ │ ├── jquery-1.8.1.min.js │ │ │ └── modernizr-2.6.1.min.js │ ├── build │ ├── doc.css │ ├── example.xml │ ├── footer.html │ ├── header.html │ ├── include-scripts.sh │ ├── retemplate.py │ ├── template.html │ ├── toc.js │ └── try.js ├── .syncignore ├── README.md ├── doctest.css ├── doctest.js ├── esprima │ ├── .travis.yml │ ├── ChangeLog │ ├── LICENSE.BSD │ ├── README.md │ ├── assets │ │ ├── codemirror │ │ │ ├── codemirror.css │ │ │ ├── codemirror.js │ │ │ └── javascript.js │ │ ├── forkme_right_red_aa0000.png │ │ ├── json2.js │ │ ├── prettify │ │ │ ├── prettify.css │ │ │ └── prettify.js │ │ ├── require.js │ │ ├── style.css │ │ └── yui │ │ │ ├── treeview-min.js │ │ │ ├── treeview-sprite.gif │ │ │ ├── treeview.css │ │ │ └── yahoo-dom-event.js │ ├── bin │ │ └── esparse.js │ ├── component.json │ ├── demo │ │ ├── checkenv.js │ │ ├── collector.html │ │ ├── collector.js │ │ ├── functiontrace.html │ │ ├── functiontrace.js │ │ ├── highlight.html │ │ ├── highlight.js │ │ ├── minify.html │ │ ├── minify.js │ │ ├── parse.css │ │ ├── parse.html │ │ ├── precedence.html │ │ ├── rewrite.html │ │ ├── rewrite.js │ │ ├── validate.html │ │ └── validate.js │ ├── doc │ │ └── index.html │ ├── esprima.js │ ├── examples │ │ ├── detectnestedternary.js │ │ ├── findbooleantrap.js │ │ └── tokendist.js │ ├── index.html │ ├── package.json │ ├── test │ │ ├── 3rdparty │ │ │ ├── XMLHttpRequest.js │ │ │ ├── acorn.js │ │ │ ├── angular-1.0.2.js │ │ │ ├── backbone-0.9.2.js │ │ │ ├── benchmark.js │ │ │ ├── codemirror-2.34.js │ │ │ ├── escodegen.js │ │ │ ├── esmorph.js │ │ │ ├── jquery-1.8.2.js │ │ │ ├── jquery.mobile-1.2.0.js │ │ │ ├── mootools-1.4.1.js │ │ │ ├── parse-js.js │ │ │ ├── platform.js │ │ │ ├── threejs-r51.js │ │ │ └── underscore-1.4.1.js │ │ ├── benchmarks.html │ │ ├── benchmarks.js │ │ ├── compare.html │ │ ├── compare.js │ │ ├── compat.html │ │ ├── compat.js │ │ ├── coverage.footer.html │ │ ├── coverage.header.html │ │ ├── coverage.html │ │ ├── index.html │ │ ├── module.html │ │ ├── module.js │ │ ├── reflect.js │ │ ├── run.js │ │ ├── runner.js │ │ └── test.js │ └── tools │ │ ├── generate-test-fixture.js │ │ ├── generate-unicode-regex.py │ │ └── update-coverage.sh ├── examples │ ├── examples-2.html │ ├── examples-2.js │ ├── examples.html │ └── node-example.js ├── index.html ├── package.json ├── reference.html ├── try.html └── tutorial.html ├── helpers.js ├── rtcpeer.html ├── rtcpeer └── tests.js ├── web.html ├── web ├── _setup.js ├── _worker.js ├── agent.js ├── core.js ├── events.js ├── helpers.js └── test-server.js ├── worker.html ├── worker ├── messaging.js ├── worker1.js └── worker2.js ├── xhrpatch.html └── xhrpatch ├── _setup.js └── requests.js /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | #*# 3 | node_modules 4 | .htaccess 5 | db 6 | .DS_Store 7 | UglifyJS2 8 | *.log 9 | build.sh 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/promises"] 2 | path = src/promises 3 | url = git@github.com:pfraze/promises.git 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | setup: clean build buildmin 2 | @echo "Done!" 3 | 4 | clean: 5 | @-rm local.js local.min.js 6 | @echo Cleaned Out Libraries 7 | 8 | build: local.js 9 | @echo Browserified library 10 | local.js: 11 | browserify src/index.js -o local.js 12 | 13 | buildmin: local.min.js 14 | @echo Built Minified Versions 15 | local.min.js: local.js 16 | @./scripts/minify.sh $@ $^ 17 | 18 | deps: uglifyjs 19 | uglifyjs: 20 | -git clone git://github.com/mishoo/UglifyJS2.git 21 | (cd UglifyJS2 && npm link .) -------------------------------------------------------------------------------- /assets/ajax_spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfrazee/local/becf1f1eafee6eed0f38034f37cc28b13cfd5724/assets/ajax_spinner.gif -------------------------------------------------------------------------------- /assets/bootstrap/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfrazee/local/becf1f1eafee6eed0f38034f37cc28b13cfd5724/assets/bootstrap/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /assets/bootstrap/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfrazee/local/becf1f1eafee6eed0f38034f37cc28b13cfd5724/assets/bootstrap/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /assets/css/docs.css: -------------------------------------------------------------------------------- 1 | 2 | #viewer-nav { width: 190px; float: left; margin-left: 25px; } 3 | #viewer { margin: 30px 20px 0 280px; max-width: 960px; } 4 | #viewer:empty { background: center 200px no-repeat url(../ajax_spinner.gif); min-height: 300px; } 5 | @media (max-width: 1300px) { 6 | #viewer-nav { width: 140px; margin-left: 0; } 7 | #viewer { margin: 30px 20px 0 190px; max-width: 960px; } 8 | } -------------------------------------------------------------------------------- /assets/css/sitewide.css: -------------------------------------------------------------------------------- 1 | body { color: #555; font-family: 'Roboto', sans-serif; font-weight: 300; } 2 | pre, code { font-family: Consolas, "Courier New", monospace; color: #5E5E5E; background: #f5f2f0; } 3 | a { color: #3184D6; } 4 | p { margin: 13px 0 17px; } 5 | blockquote { border-left: 5px solid #ddd; } 6 | blockquote p { font-size:14px } 7 | h2 { font-size:30px; border-bottom:1px solid gray; font-weight:normal; margin-top:16px } 8 | h3 { font-size:20px } 9 | 10 | .centered { text-align: center; } 11 | #hero { width: 100%; height: 450px; background: linear-gradient(rgba(31, 108, 177, 1), rgba(0, 0, 0, 0.5)), url(/assets/hero-bg.jpg) left -640px no-repeat; } 12 | @media (min-width: 1500px) { 13 | /* hero background is now too small, so lets autosize it to cover */ 14 | #hero { background-position: top left; background-size: cover; } 15 | } 16 | #hero h1 { text-align: center; color: white; font-size: 70px; padding-top: 155px; margin: 0 50px 0 0; } 17 | #hero h1 span { color: #2D9AE4; } 18 | #hero h4 { font-weight: normal; text-align: center; color: white; padding-top: 75px; margin: 0 50px 0 0; } 19 | 20 | #nav { background: #1F6CB1; box-shadow: 5px 0px 25px rgba(0,0,0,0.5); width: 100%; text-align: center; } 21 | #nav ul { font-size: 26px; margin: 0 auto; display: inline-block; padding-right: 50px; } 22 | #nav ul li { margin: 0; } 23 | #nav ul li.active { border-bottom: 3px solid white; } 24 | #nav ul li:hover { border-bottom: 3px solid white; } 25 | #nav ul li a { color: #FAFAFA; display: inline-block; padding: 20px 20px; } 26 | #nav ul li a:hover { color: #FAFAFA; text-decoration: none; } 27 | #nav #logo { display: none; color: white; font-weight: bold; position: absolute; top: 0; left: 0; font-size: 32px; padding: 20px;} 28 | #nav #logo span { color: #2D9AE4; } 29 | .is-sticky #nav #logo { display: block; } 30 | 31 | .container h3 { font-size: 24px; } 32 | .container p, .container ul li { font-size: 16px; } 33 | .container ul li { color: gray; margin-bottom: 12px; padding: 0 2px; } 34 | .container .intro { margin: 200px 20px; } 35 | .container .intro td:first-child { width: 125px; } 36 | .container .intro td:first-child img { width: 100px; } 37 | .container .overview { margin-bottom: 200px; width: 100%; } 38 | .container .overview td { vertical-align: top; } 39 | @media (min-width: 1080px) { 40 | .container.container-wide { width: 1080px; } 41 | .container .overview td div { width: 300px; margin: 0 auto; } 42 | } 43 | .container .overview td img { display: block; margin: 0 auto; padding-right: 20px; } 44 | .container .overview td:nth-child(1) { padding-right: 10px; } 45 | .container .overview td:nth-child(2) { padding: 0 10px; } 46 | .container .overview td:nth-child(3) { padding-left: 10px; } 47 | .container > .row { margin-bottom: 150px } -------------------------------------------------------------------------------- /assets/docs-agent-diagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfrazee/local/becf1f1eafee6eed0f38034f37cc28b13cfd5724/assets/docs-agent-diagram.jpg -------------------------------------------------------------------------------- /assets/docs-grimwidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfrazee/local/becf1f1eafee6eed0f38034f37cc28b13cfd5724/assets/docs-grimwidget.png -------------------------------------------------------------------------------- /assets/docs-messaging-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfrazee/local/becf1f1eafee6eed0f38034f37cc28b13cfd5724/assets/docs-messaging-diagram.png -------------------------------------------------------------------------------- /assets/docs.js: -------------------------------------------------------------------------------- 1 | var viewer = document.getElementById('viewer'); 2 | var viewNav = document.getElementById('viewer-nav'); 3 | 4 | // Load the markdown conversion worker 5 | local.spawnWorkerServer('./assets/mdworker.js', { domain: 'mdworker.js' }); 6 | 7 | function getContent() { 8 | var path = window.location.hash.slice(1) || 'README.md'; 9 | var baseUrl = (location.origin||(location.protocol+'//'+location.host)); 10 | var url = local.joinRelPath(baseUrl, path); 11 | 12 | // Update nav higlight 13 | var active = viewNav.querySelector('.active'); 14 | if (active) active.classList.remove('active'); 15 | viewNav.querySelector('a[href="#'+path+'"]').parentNode.classList.add('active'); 16 | 17 | // Get markdown 18 | local.GET(url) 19 | .then(function(res) { 20 | // Convert to HTML 21 | return local.POST(res.body, 'httpl://mdworker.js'); 22 | }) 23 | .then(function (res) { 24 | // Render 25 | viewer.innerHTML = res.body; 26 | window.scrollTo(0,0); 27 | Prism.highlightAll(); 28 | }) 29 | .fail(function (res) { 30 | console.error('Failed loading '+path, res); 31 | viewer.innerHTML = '
Foo
81 | 82 | Foo 83 | ``` 84 | 85 | Currently, "a" is the only supported alias, but "button" is planned for future releases to add form-submit behavior to arbitrary elements. 86 | 87 | --- 88 | 89 | ### File Uploads 90 | 91 | If a form includes an ``, Local.js will use the `FileReader` API to load the file and include it in the request body. This is an asyncronous process, so you should call `finishPayloadFileReads()` before dispatching the request. 92 | 93 | ```javascript 94 | document.body.addEventListener('request', function(e) { 95 | local.util.finishPayloadFileReads(e.detail) 96 | .then(function(request) { 97 | local.dispatch(request); 98 | }); 99 | }); 100 | 101 | ``` 102 | 103 | ### local.util.finishPayloadFileReads(request) 104 | 105 | - `request`: required `local.Request` 106 | - returns `local.Promise` -------------------------------------------------------------------------------- /docs/en/0.6.2/api/bridgeserver.md: -------------------------------------------------------------------------------- 1 | BridgeServer 2 | ============ 3 | 4 | --- 5 | 6 | Descends from `local.Server`. 7 | 8 | Base type for all servers which pipe requests between separated environments (eg WorkerBridgeServer, RTCBridgeServer). Requires the channel between the environments to be reliable and capable of transporting arbitrarily-sized messages. 9 | 10 | ## local.BridgeServer 11 | 12 | ### .isChannelActive() 13 | 14 | - returns boolean 15 | 16 | Indicates whether the channel is ready. If false, new outgoing messages will be buffered. Should be overridden. 17 | 18 | --- 19 | 20 | ### .channelSendMsg(msg) 21 | 22 | - `msg`: required string 23 | 24 | Sends the given message to the remote environment. Should be overridden. 25 | 26 | ```javascript 27 | WorkerServer.prototype.channelSendMsg = function(msg) { 28 | this.worker.postMessage(msg); 29 | }; 30 | ``` 31 | 32 | --- 33 | 34 | ### .onChannelMessage(msg) 35 | 36 | - `msg`: required string 37 | 38 | Handles messages from the remote environment. Should be called by the descendent type on new messages. 39 | 40 | --- 41 | 42 | ### .handleRemoteRequest(req, res) 43 | 44 | - `req`: required local.Request 45 | - `res`: required local.Response 46 | 47 | Called to handle requests by the remote environment. Should be overridden. 48 | 49 | --- 50 | 51 | ### .flushBufferedMessages() 52 | 53 | Flushes any messages which were buffered before the channel was active. Should be called by the descendent type on channel open. 54 | 55 | --- 56 | 57 | ### .useMessageReordering(v) 58 | 59 | - `v`: required boolean 60 | 61 | Enables/disables head-of-line blocking in streams through message-numbering. Useful for channels which do not guarantee order. -------------------------------------------------------------------------------- /docs/en/0.6.2/api/contenttypes.md: -------------------------------------------------------------------------------- 1 | contentTypes 2 | ============ 3 | 4 | --- 5 | 6 | A registry of de/serializers for various mimetypes. Includes "application/json", "application/x-www-form-urlencoded", and "text/event-stream" by default. 7 | 8 | ```javascript 9 | local.contentTypes.register('application/json', 10 | function (obj) { 11 | try { 12 | return JSON.stringify(obj); 13 | } catch (e) { 14 | return ''; 15 | } 16 | }, 17 | function (str) { 18 | try { 19 | return JSON.parse(str); 20 | } catch (e) { 21 | return null; 22 | } 23 | } 24 | ); 25 | local.contentTypes.serialize('application/json', { foo:'bar' }); 26 | // => '{ "foo":"bar" }' 27 | local.contentTypes.deserialize('application/json', '{ "foo":"bar" }'); 28 | // => { foo:'bar' } 29 | ``` 30 | 31 | De/serializers are chosen by best match, according to the specificity of the provided mimetype. For instance, if 'application/foobar+json' is used, it will search for 'application/foobar+json', then 'application/json', then 'application'. If no match is found, the given parameter is returned as-is. 32 | 33 | ## local.contentTypes 34 | 35 | ### .register(mimetype, serializeFn, deserializeFn) 36 | 37 | - `mimetype`: required string 38 | - `serializeFn`: required function(obj) 39 | - `deserializeFn`: required function(str) 40 | 41 | ### .serialize(mimetype, object) 42 | 43 | - `mimetype`: required string 44 | - `object`: required object 45 | - returns string 46 | 47 | ### .deserialize(mimetype, string) 48 | 49 | - `mimetype`: required string 50 | - `string`: required string 51 | - returns object -------------------------------------------------------------------------------- /docs/en/0.6.2/api/dispatch.md: -------------------------------------------------------------------------------- 1 | dispatch() 2 | ========== 3 | 4 | --- 5 | 6 | Sends a new request and returns a promise for the response. 7 | 8 | ```javascript 9 | var resPromise = local.dispatch({ 10 | method: 'POST', 11 | url: 'httpl://myserver', 12 | headers: { 'content-type': 'application/json', accept: 'text/html' }, 13 | body: myMessage 14 | }); 15 | resPromise.then( 16 | function(res) { 17 | assert(res.status >= 200 && res.status <= 399); 18 | }, 19 | function(res) { 20 | assert(res.status >= 400 && res.status <= 599); 21 | } 22 | ); 23 | ``` 24 | 25 | ### local.http.dispatch(request) 26 | 27 | `request` must fit the following schema description: 28 | 29 | ``` 30 | { 31 | url: required string 32 | method: optional string; defaults to 'GET' 33 | query: optional object; a map of query parameters to add to the url 34 | headers: optional object; should include a (all lower-case) map of headers to values 35 | body: optional object; the request payload 36 | stream: optional boolean; specifies whether the response should be given in chunks 37 | binary: optional boolean; receive a binary arraybuffer response? Only applies to HTTP/S 38 | } 39 | ``` 40 | 41 | All requests are sent on the next tick. 42 | 43 | » Request, » Response 44 | 45 | Local includes the following common request sugars: 46 | 47 | - `local.HEAD(request)` 48 | - `local.GET(request)` 49 | - `local.DELETE(request)` 50 | - `local.SUBSCRIBE(request)` 51 | - `local.POST(body, request)` 52 | - `local.PUT(body, request)` 53 | - `local.PATCH(body, request)` 54 | - `local.NOTIFY(body, request)` 55 | 56 | Any capitalized attributes in the request object are treated as headers and moved into the `headers` object on dispatch. Underscores are converted into dashes: 57 | 58 | ```javascript 59 | local.POST(mydata, { url: 'http://grimwire.com', Content_Type: 'application/json', Accept: 'text/html' }) 60 | ``` 61 | 62 | --- 63 | 64 | ### Server Functions 65 | 66 | Server functions are given copies of the `local.Request` object, but with `url` replaced with `path`. 67 | 68 | ```javascript 69 | local.addServer('myserver', function(req, res) { 70 | console.log(req); /* => 71 | { 72 | path: '/', 73 | method: 'GET', 74 | headers: { ... } 75 | } 76 | */ 77 | req.on('end', function() { 78 | // ... 79 | }); 80 | }); 81 | ``` 82 | 83 | All servers are called when the request headers are first dispatched, not when the request ends. This means you must wait for the 'end' event if you want to use the request body. 84 | 85 | --- 86 | 87 | ### Request/Response Bodies 88 | 89 | In the case of both request and response streams, the body is automatically buffered. When the stream ends, Local.js will use the 'content-type' header to attempt deserialization. It will set the `body` attribute of the request/response to the resulting object (if parsing is successful) or string (if not). 90 | 91 | You can add new content-type support with `local.contentTypes.register()`. 92 | 93 | » contentTypes 94 | 95 | --- 96 | 97 | ### Request Streaming 98 | 99 | If you want to stream the body of the request, use a `local.Request` object in `dispatch()`, then use the request's API to add data and finish the stream. 100 | 101 | ```javascript 102 | var req = new local.Request({ 103 | method: 'POST', 104 | url: 'httpl://myserver', 105 | headers: { 'content-type': 'application/json', accept: 'text/html' } 106 | }); 107 | local.http.dispatch(req); 108 | req.send(chunk1); 109 | req.send(chunk2); 110 | req.end(); 111 | ``` 112 | 113 | You must always call end() to complete the request when streaming. 114 | 115 | --- 116 | 117 | ### Response Streaming 118 | 119 | By default, Local.js will fulfill the response promise after the response stream ends. However, if `stream` is set to true, it will fulfill when the headers arrive, allowing you to handle the chunks individually. 120 | 121 | ```javascript 122 | local.dispatch({ url: 'httpl://myserver', headers: { accept: 'text/plain' }, stream: true }) 123 | .then(function(res) { 124 | res.on('data', function(chunk) { /* ... */ }); 125 | res.on('end', function(chunk) { /* ... */ }); 126 | }); 127 | ``` -------------------------------------------------------------------------------- /docs/en/0.6.2/api/eventemitter.md: -------------------------------------------------------------------------------- 1 | EventEmitter 2 | ============ 3 | 4 | --- 5 | 6 | Event emitter utility class. 7 | 8 | ```javascript 9 | var emitter = new local.util.EventEmitter(); 10 | emitter.on(['foo', 'bar'], console.log.bind(console, 'foobar')); 11 | emitter.on('baz', console.log.bind(console, 'baz')); 12 | emitter.emit('foo', 'hello'); 13 | // => foobar hello 14 | emitter.emit('baz', 'world'); 15 | // => baz world 16 | ``` 17 | 18 | ### local.util.mixinEventEmitter(obj) 19 | 20 | - `obj`: required object 21 | 22 | Calls the EventEmitter constructor on the object and mixes in all of the methods. 23 | 24 | ## local.util.EventEmitter 25 | 26 | ### .emit(eventName, args...) 27 | 28 | - `eventName`: required string 29 | - `args`: optional, each argument after `eventName` will be applied to the listener functions 30 | 31 | Returns `false` if no handlers are registered to the `eventName` and `true` otherwise. 32 | 33 | --- 34 | 35 | ### .on/addListener(eventName, listenerFn) 36 | 37 | - `eventName`: required string 38 | - `listenerFn`: required function 39 | - returns `this` 40 | 41 | --- 42 | 43 | ### .once(eventName, listenerFn) 44 | 45 | - `eventName`: required string 46 | - `listenerFn`: required function 47 | - returns `this` 48 | 49 | --- 50 | 51 | ### .removeListener(eventName, listenerFn) 52 | 53 | - `eventName`: required string 54 | - `listenerFn`: required function 55 | - returns `this` 56 | 57 | --- 58 | 59 | ### .removeAllListeners(eventName) 60 | 61 | - `eventName`: required string 62 | - `listenerFn`: required function 63 | - returns `this` 64 | 65 | --- 66 | 67 | ### .suspendEvents() 68 | 69 | Adds to the lock counter on the emitter, causing it to buffers all received events until `resumeEvents()` releases the lock. 70 | 71 | --- 72 | 73 | ### .resumeEvents() 74 | 75 | Decrements the lock counter. If the lock counter reaches 0, buffered events are fired (in order received) and future events are fired immediately. 76 | 77 | --- 78 | 79 | ### .isSuspended() 80 | 81 | - returns bool -------------------------------------------------------------------------------- /docs/en/0.6.2/api/eventhost.md: -------------------------------------------------------------------------------- 1 | EventHost 2 | ========= 3 | 4 | Manages response streams and provides functions to send event chunks en masse. 5 | 6 | ```javascript 7 | var myevents = new local.EventHost(); 8 | local.addServer('eventhost', function(req, res) { 9 | res.writeHead(200, 'ok', { 'content-type': 'text/event-stream' }); 10 | myevents.addStream(res); 11 | }); 12 | // ... 13 | myEvents.emit('news', { foo: 'bar' }); 14 | ``` 15 | 16 | ### local.EventHost() 17 | 18 | Creates a new instance. 19 | 20 | ## local.EventHost 21 | 22 | ### .addStream(response) 23 | 24 | - `response`: required local.Response, the stream 25 | - returns number 26 | 27 | Adds the stream as a recipient of future events. The returned number can be used as an identifier for the stream in future calls to the EventHost. 28 | 29 | ### .endStream(response) 30 | 31 | - `response`: required number|local.Response 32 | 33 | Closes the stream and removes it from the EventHost. 34 | 35 | ### .endAllStreams() 36 | 37 | Closes all streams and removes them from the EventHost. 38 | 39 | ### .emit(event, data, opts) 40 | 41 | - `event`: required string, the event name 42 | - `data`: optional any, the data to send with the event 43 | - `ops.exclude`: optional number|local.Response|Array(number)|Array(local.Response), streams which should not receive the event 44 | 45 | ### .emitTo(response, event, data) 46 | 47 | - `response`: required number|local.Response, the stream that should receive the event 48 | - `event`: required string, the event name 49 | - `data`: optional any, the data to send with the event -------------------------------------------------------------------------------- /docs/en/0.6.2/api/eventstream.md: -------------------------------------------------------------------------------- 1 | EventStream 2 | =========== 3 | 4 | --- 5 | 6 | Wraps a response stream with an event-listening interface. Created by `local.subscribe()`. Descends from `local.util.EventEmitter`. 7 | 8 | ```javascript 9 | var news = local.subscribe('http://myhost.com/news'); 10 | news.on('update', console.log.bind(console)); 11 | // { event: 'update', data: 'something has happened!' } 12 | ``` 13 | 14 | ## local.EventStream 15 | 16 | ### .close() 17 | 18 | Closes the stream. 19 | 20 | ### .reconnect() 21 | 22 | Establishes the event-stream by redispatching the original request. 23 | 24 | ### .getUrl() 25 | 26 | - returns string, the URL hosting the event stream -------------------------------------------------------------------------------- /docs/en/0.6.2/api/httpheaders.md: -------------------------------------------------------------------------------- 1 | httpHeaders 2 | =========== 3 | 4 | --- 5 | 6 | A registry of de/serializers for various headers. Includes "link" and "accept" by default. 7 | 8 | ```javascript 9 | local.httpHeaders.register('link', 10 | function (obj) { /* ... */ }, 11 | function (str) { /* ... */ } 12 | ); 13 | local.httpHeaders.serialize('link', { href: 'httpl://foo', rel: 'service' }); 14 | // => 'brought to you by doctest.js
17 | 18 |5 | You can download this project in either 6 | zip or 7 | tar formats. 8 |
9 | 10 |You can also clone the project with Git 11 | by running: 12 |
$ git clone git://github.com/ianb/doctestjs13 | 14 | 15 | 19 | 20 | 21 | 22 | 26 | 31 | -------------------------------------------------------------------------------- /test/doctest/.resources/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
Note: Only regular expression literals and objects created with RegExp
are considered.
Type ECMAScript code:
31 | 43 |The above code editor is based on CodeMirror.
44 | 45 |Using Esprima version .
46 | 47 |Type ECMAScript code:
36 | 59 |The above code editor is based on CodeMirror.
60 | 61 |62 | 63 |
64 | 65 |Instrumentation for each function will be added with the Insert tracing button. Pressing the Run button will execute the code (using JavaScript eval
) with the instrumentation, and then call counts for each function will be displayed (sorted by the number of calls). Warning: do not run untrusted code!
No result yet.
Using Esprima version .
70 | 73 | 74 | 75 |Type ECMAScript code and place the cursor in an identifier.
44 | Note: Scope is not handled properly yet, see issue 98.
The above code editor is based on CodeMirror.
61 | 62 | 63 | 64 |Using Esprima version .
65 | 66 | 69 | 70 | 71 |Type ECMAScript code in the editor. Press Minify button to shorten the code 36 | using Escodegen project.
37 | 38 | 56 | 57 | 58 | 59 |The above code editor is based on CodeMirror.
60 | 61 | 62 | 63 | 64 | 65 | 68 | 69 | 70 |Type ECMAScript code in the editor. Press Rewrite button to get the code 36 | rewritten using Escodegen project.
37 | 38 | 58 | 59 |Indent with: 60 | 61 | 62 | 63 |
64 |String literal quotes: 65 | 66 | 67 | 68 |
69 | 70 | 71 | 72 | 73 |The above code editor is based on CodeMirror.
74 | 75 | 76 | 77 |Notes:
78 |Esprima version .
43 | 44 |Type ECMAScript code:
45 | 62 |The above code editor is based on CodeMirror.
63 | 64 |No result yet.
Found ' + result.length + ':
'; 23 | for (i = 0; i < result.length; i += 1) { 24 | str += '' + result[i].message + '
'; 25 | } 26 | } else { 27 | str = 'No syntax error.
'; 28 | } 29 | } catch (e) { 30 | str = e.name + ': ' + e.message; 31 | } 32 | document.getElementById('result').innerHTML = str; 33 | 34 | validateId = undefined; 35 | }, delay || 811); 36 | } 37 | 38 | window.onload = function () { 39 | var id, el; 40 | 41 | id = function (i) { 42 | return document.getElementById(i); 43 | }; 44 | 45 | el = id('version'); 46 | if (typeof el.innerText === 'string') { 47 | el.innerText = esprima.version; 48 | } else { 49 | el.textContent = esprima.version; 50 | } 51 | try { 52 | validate(1); 53 | } catch (e) { } 54 | }; 55 | 56 | try { 57 | window.checkEnv(); 58 | 59 | // This is just testing, to detect whether CodeMirror would fail or not 60 | window.editor = CodeMirror.fromTextArea(document.getElementById("test")); 61 | 62 | window.editor = CodeMirror.fromTextArea(document.getElementById("code"), { 63 | lineNumbers: true, 64 | matchBrackets: true, 65 | onChange: validate 66 | }); 67 | } catch (e) { 68 | // CodeMirror failed to initialize, possible in e.g. old IE. 69 | document.getElementById('codemirror').innerHTML = ''; 70 | document.getElementById('code').onchange = validate; 71 | document.getElementById('code').onkeydown = validate; 72 | } finally { 73 | document.getElementById('testbox').parentNode.removeChild(document.getElementById('testbox')); 74 | } 75 | -------------------------------------------------------------------------------- /test/doctest/esprima/examples/detectnestedternary.js: -------------------------------------------------------------------------------- 1 | // Usage: node detectnestedternary.js /path/to/some/directory 2 | // For more details, please read http://esprima.org/doc/#nestedternary 3 | 4 | /*jslint node:true sloppy:true plusplus:true */ 5 | 6 | var fs = require('fs'), 7 | esprima = require('../esprima'), 8 | dirname = process.argv[2]; 9 | 10 | 11 | // Executes visitor on the object and its children (recursively). 12 | function traverse(object, visitor) { 13 | var key, child; 14 | 15 | visitor.call(null, object); 16 | for (key in object) { 17 | if (object.hasOwnProperty(key)) { 18 | child = object[key]; 19 | if (typeof child === 'object' && child !== null) { 20 | traverse(child, visitor); 21 | } 22 | } 23 | } 24 | } 25 | 26 | // http://stackoverflow.com/q/5827612/ 27 | function walk(dir, done) { 28 | var results = []; 29 | fs.readdir(dir, function (err, list) { 30 | if (err) { 31 | return done(err); 32 | } 33 | var i = 0; 34 | (function next() { 35 | var file = list[i++]; 36 | if (!file) { 37 | return done(null, results); 38 | } 39 | file = dir + '/' + file; 40 | fs.stat(file, function (err, stat) { 41 | if (stat && stat.isDirectory()) { 42 | walk(file, function (err, res) { 43 | results = results.concat(res); 44 | next(); 45 | }); 46 | } else { 47 | results.push(file); 48 | next(); 49 | } 50 | }); 51 | }()); 52 | }); 53 | } 54 | 55 | walk(dirname, function (err, results) { 56 | if (err) { 57 | console.log('Error', err); 58 | return; 59 | } 60 | 61 | results.forEach(function (filename) { 62 | var shortname, first, content, syntax; 63 | 64 | shortname = filename; 65 | first = true; 66 | 67 | if (shortname.substr(0, dirname.length) === dirname) { 68 | shortname = shortname.substr(dirname.length + 1, shortname.length); 69 | } 70 | 71 | function report(node, problem) { 72 | if (first === true) { 73 | console.log(shortname + ': '); 74 | first = false; 75 | } 76 | console.log(' Line', node.loc.start.line, ':', problem); 77 | } 78 | 79 | function checkConditional(node) { 80 | var condition; 81 | 82 | if (node.consequent.type === 'ConditionalExpression' || 83 | node.alternate.type === 'ConditionalExpression') { 84 | 85 | condition = content.substring(node.test.range[0], node.test.range[1]); 86 | if (condition.length > 20) { 87 | condition = condition.substring(0, 20) + '...'; 88 | } 89 | condition = '"' + condition + '"'; 90 | report(node, 'Nested ternary for ' + condition); 91 | } 92 | } 93 | 94 | try { 95 | content = fs.readFileSync(filename, 'utf-8'); 96 | syntax = esprima.parse(content, { tolerant: true, loc: true, range: true }); 97 | traverse(syntax, function (node) { 98 | if (node.type === 'ConditionalExpression') { 99 | checkConditional(node); 100 | } 101 | }); 102 | } catch (e) { 103 | } 104 | 105 | }); 106 | }); 107 | -------------------------------------------------------------------------------- /test/doctest/esprima/examples/tokendist.js: -------------------------------------------------------------------------------- 1 | /*jslint node:true */ 2 | var fs = require('fs'), 3 | esprima = require('../esprima'), 4 | files = process.argv.splice(2), 5 | histogram, 6 | type; 7 | 8 | histogram = { 9 | Boolean: 0, 10 | Identifier: 0, 11 | Keyword: 0, 12 | Null: 0, 13 | Numeric: 0, 14 | Punctuator: 0, 15 | RegularExpression: 0, 16 | String: 0 17 | }; 18 | 19 | files.forEach(function (filename) { 20 | 'use strict'; 21 | var content = fs.readFileSync(filename, 'utf-8'), 22 | tokens = esprima.parse(content, { tokens: true }).tokens; 23 | 24 | tokens.forEach(function (token) { 25 | histogram[token.type] += 1; 26 | }); 27 | }); 28 | 29 | for (type in histogram) { 30 | if (histogram.hasOwnProperty(type)) { 31 | console.log(type, histogram[type]); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/doctest/esprima/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "esprima", 3 | "description": "ECMAScript parsing infrastructure for multipurpose analysis", 4 | "homepage": "http://esprima.org", 5 | "main": "esprima.js", 6 | "bin": { 7 | "esparse": "./bin/esparse.js" 8 | }, 9 | "version": "1.1.0-dev", 10 | "engines": { 11 | "node": ">=0.4.0" 12 | }, 13 | "maintainers": [{ 14 | "name": "Ariya Hidayat", 15 | "email": "ariya.hidayat@gmail.com", 16 | "web": "http://ariya.ofilabs.com" 17 | }], 18 | "repository": { 19 | "type": "git", 20 | "url": "http://github.com/ariya/esprima.git" 21 | }, 22 | "licenses": [{ 23 | "type": "BSD", 24 | "url": "http://github.com/ariya/esprima/raw/master/LICENSE.BSD" 25 | }], 26 | "scripts": { 27 | "test": "node test/run.js", 28 | "benchmark": "node test/benchmarks.js", 29 | "benchmark-quick": "node test/benchmarks.js quick" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/doctest/esprima/test/benchmarks.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |Time measurement is carried out using Benchmark.js.
36 | 37 |Esprima version .
38 | 39 |Please wait...
40 | 41 |42 | 43 | 44 |
45 | 46 | 47 | 48 |Note: On a modern machine and up-to-date web browsers,
49 | running full benchmarks suite takes around 1 minute.
50 | For the quick benchmarks, the running time is only about 15 seconds.
Time measurement is carried out using Benchmark.js.
36 | 37 |Esprima version .
38 | 39 |Please wait... 40 |
41 | 42 | 43 | 44 | 45 |Warning: Since each parser may have a different format for the syntax tree, the speed is not fully comparable (the cost of constructing different result is not taken into account). These tests exist only to ensure that Esprima parser is not ridiculously slow compare to other parsers.
46 | 47 |parse-js is the parser used in UglifyJS v1. It's a JavaScript port of the Common LISP version. This test uses parse-js
from UglifyJS version 1.3.2 (June 26 2012).
Acorn is a compact stand-alone JavaScript parser. This test uses Acorn revision 0590d122 (dated Oct 3 2012).
50 | 51 |More comparison variants will be added in the near future.
52 | 53 | 56 |Esprima version .
26 |The following tests are to ensure that the syntax tree is compatible to 27 | that produced by Mozilla SpiderMonkey 28 | Parser reflection.
29 |Please wait...
30 | 31 | 34 |