diff --git a/README.md b/README.md deleted file mode 100644 index af1fca1..0000000 --- a/README.md +++ /dev/null @@ -1,170 +0,0 @@ -# Unnamed.js - -A minimal node http server framework by [Mart Anthony Salazar](https://github.com/mart-anthony-stark) - -- [Getting Started](https://github.com/mart-anthony-stark/Unnamed.js#getting-started) -- [Routes](https://github.com/mart-anthony-stark/Unnamed.js#routes) -- [Request](https://github.com/mart-anthony-stark/Unnamed.js#request-object) -- [Response](https://github.com/mart-anthony-stark/Unnamed.js#response-methods) -- [Modular Routing](https://github.com/mart-anthony-stark/Unnamed.js#router-for-modular-code) -- [Combine Routers](https://github.com/mart-anthony-stark/Unnamed.js#combine-routers) -- [Setup Demo](https://github.com/mart-anthony-stark/Unnamed.js/tree/main/demoV2) - -### Getting started - -Call the unnamed function and assign it to a variable - -```javascript -const unnamed = require("./src"); - -const server = unnamed({ - port: 3000, - init: () => { - // This will run as the server initializes - console.log("App is running"); - }, -}); -``` - -![server](https://github.com/mart-anthony-stark/Unnamed.js/blob/main/docs/start%20server.png?raw=true) - -### Routes - -This framework supports the 5 commonly-used HTTP request methods. The methods can be accessed through the returned server object - -- GET -- POST -- PUT -- PATCH -- DELETE - -```javascript -server.GET("/", (request, response) => { - response.code(200).send({ method: request.method, msg: "Hello world" }); -}); -server.POST("/", (request, response) => { - response.code(200).send({ method: request.method, msg: "Hello world" }); -}); -server.PUT("/", (request, response) => { - response.code(200).send({ method: request.method, msg: "Hello world" }); -}); -server.PATCH("/", (request, response) => { - response.code(200).send({ method: request.method, msg: "Hello world" }); -}); -server.DELETE("/", (request, response) => { - response.code(200).send({ method: request.method, msg: "Hello world" }); -}); -``` - -### Request object - -- query - endpoint queries can be accessed through request.query object - - - Sample endpoint: http://localhost:3000/user?name=mart&age=19 - - ```javascript - server.GET("/user", (request, response) => { - res.send({ - username: request.query.name, - age: request.query.age, - }); - }); - ``` - -- params - Params object contains parameter values parsed from the URL path - - - Sample endpoint: http://localhost:3000/user/123456 - - ```javascript - server.GET("/user/:id", (request, response) => { - res.send({ - userId: request.params.id, - }); - }); - ``` - -- body - The read-only body property of the Request interface contains a ReadableStream with the body contents that have been added to the request. - -```javascript -server.POST("/post", async (request, response) => { - const post = await new Post(request.body).save(); - response.send(post); -}); -``` - -> Note: Unnamed.js has a builtin body parser that listens to data event and attaches to request object. You don't need to install external library such as body parser. - -### Response methods - -- code() - This method sets the response status code. If you want to know more about HTTP status codes, visit [MDN Web Documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) - - Syntax: - ```typescript - const status: number = 200; - response.code(status); - ``` -- send() - This method basically sends the HTTP response. The body parameter can be a String or a Buffer object or an object or an Array. It accepts a single parameter body that describe the body which is to be sent in the response. It also automatically parse the body into JSON if possible. - - Syntax: - ```javascript - const body = { - id: 123456, - name: Mart Anthony Salazar, - age: 19 - } - response.send(body) - ``` - -### Router for modular code - -the server object comes up with a registerRouter() method to include routes from another javascript file - -```javascript -server.registerRouter({ - prefix: "users", // will be added to the URL path - router: require("./routes/user.route"), -}); -``` - -- Inside 'routes/user.route.js' file, define a function that accepts 'route' parameter - -```javascript -const userRouter = (route) => { - route.GET("/all", { beforeEnter: [] }, (req, res) => { - res.send({ - data: "this is a user router", - method: req.method, - url: req.url, - }); - }); -}; - -module.exports = userRouter; -``` - -- Since there is a prefix indicated in the registerRouter() method, sample endpoint will look like this: http://localhost:5000/user/all - -### Combine Routers - -Another option for registering routers is to combine them using combineRouters() method. - -- For example, you have two routers: auth and users - -```javascript -// app.js -server.combineRouters(require("./routes")); -``` - -```javascript -// routes/index.js -const routes = [ - { - prefix: "users", - router: require("./user.route"), - }, - { - prefix: "auth", - router: require("./auth.route"), - }, -]; - -module.exports = routes; -``` diff --git a/demo/app.js b/demo/app.js deleted file mode 100644 index ca67866..0000000 --- a/demo/app.js +++ /dev/null @@ -1,53 +0,0 @@ -const unnamed = require("../src"); - -const server = unnamed({ - port: 3000, - init: () => { - console.log("App is running"); - }, -}); - -server.middleware((req, res, done) => { - console.log("This is middleware 1"); - req.user = "mart"; - done(); -}); - -server.middleware((req, res, done) => { - console.log("This is middleware 2"); - console.log(req.user); - done(); -}); - -server.registerRouter({ - prefix: "user", - router: require("./user.route"), -}); - - -server.GET("/", (req, res) => { - console.log(req.user); - console.log({ query: req.query }); - res.code(401).send({ data: { user: req.user }, error: "Unauthorized" }); -}); - -server.GET("/:id", (req, res) => { - console.log(req.params); - res.code(200).send({ id: req.params.id }); -}); - -server.POST("/", (req, res) => { - res.code(200).send({ Created: req.body }); -}); - -server.PUT("/", (req, res) => { - res.send({ msg: "Modified" }); -}); - -server.PATCH("/", (req, res) => { - res.code(200).send({ msg: "Updated" }); -}); - -server.DELETE("/", (req, res) => { - res.code(200).send("Ok"); -}); diff --git a/demo/user.route.js b/demo/user.route.js deleted file mode 100644 index 633a6c6..0000000 --- a/demo/user.route.js +++ /dev/null @@ -1,50 +0,0 @@ -const userRouter = (route) => { - route.GET("/", { beforeEnter: [] }, (req, res) => { - res.send({ - data: "this is a user router", - method: req.method, - url: req.url, - }); - }); - - route.GET("/name", (req, res) => { - res.send({ - data: "this is a user router", - method: req.method, - url: req.url, - }); - }); - route.POST("/", (req, res) => { - res.send({ - data: "this is a user router", - method: req.method, - url: req.url, - body: req.body, - }); - }); - route.PUT("/", (req, res) => { - res.send({ - data: "this is a user router", - method: req.method, - url: req.url, - body: req.body, - }); - }); - route.PATCH("/", (req, res) => { - res.send({ - data: "this is a user router", - method: req.method, - url: req.url, - body: req.body, - }); - }); - route.DELETE("/", (req, res) => { - res.send({ - data: "this is a user router", - method: req.method, - url: req.url, - body: req.body, - }); - }); -}; -module.exports = userRouter; diff --git a/demoV2/app.js b/demoV2/app.js deleted file mode 100644 index a131ffe..0000000 --- a/demoV2/app.js +++ /dev/null @@ -1,29 +0,0 @@ -const unnamed = require("../src"); -const mongoose = require("mongoose"); -const cors = require("cors"); - -// env variables -require("dotenv").config({}); - -const server = unnamed({ - port: process.env.PORT || 5000, - init: async () => { - try { - mongoose.connect(process.env.DB_URI, { - useNewUrlParser: true, - useUnifiedTopology: true, - }); - console.log("Connected to database"); - } catch (error) { - console.log(error); - } - }, -}); - -server.middleware(cors("*")); - -server.combineRouters(require("./routes")); - -server.GET("/", (req, res) => { - res.send("hello"); -}); diff --git a/demoV2/controllers/user.controller.js b/demoV2/controllers/user.controller.js deleted file mode 100644 index 93c31a5..0000000 --- a/demoV2/controllers/user.controller.js +++ /dev/null @@ -1,8 +0,0 @@ -const User = require("../models/User.model"); - -module.exports = { - getAllUsers: async (req, res) => { - const users = await User.find(); - res.send(users); - }, -}; diff --git a/demoV2/models/User.model.js b/demoV2/models/User.model.js deleted file mode 100644 index 9dd7ce8..0000000 --- a/demoV2/models/User.model.js +++ /dev/null @@ -1,14 +0,0 @@ -const mongoose = require("mongoose"); - -const userSchema = new mongoose.Schema( - { - username: { type: String, required: true, unique: true }, - email: { type: String, required: true, unique: true }, - password: { type: String, required: true, minlength: 8 }, - img: { type: String }, - role: { type: String, default: "user", enum: ["user", "admin"] }, - }, - { timestamps: true } -); - -module.exports = mongoose.model("User", userSchema); diff --git a/demoV2/routes/auth.route.js b/demoV2/routes/auth.route.js deleted file mode 100644 index 89608ea..0000000 --- a/demoV2/routes/auth.route.js +++ /dev/null @@ -1,7 +0,0 @@ -const authRouter = (router) => { - router.GET("/login", (request, response) => { - response.send("login route"); - }); -}; - -module.exports = authRouter; diff --git a/demoV2/routes/index.js b/demoV2/routes/index.js deleted file mode 100644 index 598d053..0000000 --- a/demoV2/routes/index.js +++ /dev/null @@ -1,12 +0,0 @@ -const routes = [ - { - prefix: "users", - router: require("./user.route"), - }, - { - prefix: "auth", - router: require("./auth.route"), - }, -]; - -module.exports = routes; diff --git a/demoV2/routes/user.route.js b/demoV2/routes/user.route.js deleted file mode 100644 index 07bb5e8..0000000 --- a/demoV2/routes/user.route.js +++ /dev/null @@ -1,7 +0,0 @@ -const userController = require("../controllers/user.controller"); - -const userRouter = (router) => { - router.GET("/", userController.getAllUsers); -}; - -module.exports = userRouter; diff --git a/docs/UNNAMED.JS-MD.png b/docs/UNNAMED.JS-MD.png new file mode 100644 index 0000000..2408e89 Binary files /dev/null and b/docs/UNNAMED.JS-MD.png differ diff --git a/docs/UNNAMED.JS-SM.png b/docs/UNNAMED.JS-SM.png new file mode 100644 index 0000000..431792c Binary files /dev/null and b/docs/UNNAMED.JS-SM.png differ diff --git a/docs/comparison.png b/docs/comparison.png new file mode 100644 index 0000000..a6ed4a1 Binary files /dev/null and b/docs/comparison.png differ diff --git a/docs/latency table.png b/docs/latency table.png new file mode 100644 index 0000000..5913ed8 Binary files /dev/null and b/docs/latency table.png differ diff --git a/docs/latency.png b/docs/latency.png new file mode 100644 index 0000000..f0ddf23 Binary files /dev/null and b/docs/latency.png differ diff --git a/src/index.js b/index.js similarity index 100% rename from src/index.js rename to index.js diff --git a/package.json b/package.json deleted file mode 100644 index 99516d8..0000000 --- a/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "martify", - "version": "1.0.0", - "description": "A minimal node http server framework", - "main": "app.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/mart-anthony-stark/Node-http-library-implementation.git" - }, - "author": "Mart Salazar | mart-anthony-stark", - "license": "ISC", - "bugs": { - "url": "https://github.com/mart-anthony-stark/Node-http-library-implementation/issues" - }, - "homepage": "https://github.com/mart-anthony-stark/Node-http-library-implementation#readme" -} diff --git a/src/lib/bodyParser.js b/src/lib/bodyParser.js deleted file mode 100644 index 2e56941..0000000 --- a/src/lib/bodyParser.js +++ /dev/null @@ -1,17 +0,0 @@ -async function bodyParser(req) { - // Listening to data event and attatch to req.body - return new Promise((resolve, reject) => { - let body = ""; - req.on("data", (chunk) => { - body += chunk.toString(); - }); - req.on("end", () => { - if (body !== "") { - req.body = JSON.parse(body); - resolve(); - } else resolve(); - }); - }); -} - -module.exports = bodyParser; diff --git a/src/lib/findRoute.js b/src/lib/findRoute.js deleted file mode 100644 index 3334577..0000000 --- a/src/lib/findRoute.js +++ /dev/null @@ -1,14 +0,0 @@ -const findRoute = (routes, method, url) => { - // delete extra slash to end of the entered url - if (url.substring(url.length - 1) === "/" && url.length !== 1) { - url = url.slice(0, url.length - 1); - } - const route = routes.find((route) => { - return route.method === method && route.url.match(url); - }); - - if (!route) return null; - return { handler: route.handler, params: route.url.match(url) }; -}; - -module.exports = findRoute; diff --git a/src/lib/index.js b/src/lib/index.js deleted file mode 100644 index a1ef6bf..0000000 --- a/src/lib/index.js +++ /dev/null @@ -1,195 +0,0 @@ -const http = require("http"); -const handleMiddlewares = require("./middleware"); -const findRoute = require("./findRoute"); -const bodyParser = require("./bodyParser"); -const Route = require("./route-parser"); -const queryParser = require("./query-parser"); - -module.exports = (() => { - let routes = []; - let middlewares = []; - - const insertRoute = (method, url, options, handler) => { - // DELETES EXTRA SLASH IN THE TAIL OF THE PATH - if (url.substring(url.length - 1) === "/" && url.length !== 1) - url = url = url.slice(0, url.length - 1); - - routes.push({ url: new Route(url), method, handler, options }); - }; - - const app = (options) => { - const middleware = (middlewareHandler) => { - if (typeof middleware == "function") middlewares.push(middlewareHandler); - }; - - const get = (route, options = {}, handler) => - insertRoute("get", route, handler, options); - const post = (route, options = {}, handler) => - insertRoute("post", route, handler, options); - const put = (route, options = {}, handler) => - insertRoute("put", route, handler, options); - const patch = (route, options = {}, handler) => - insertRoute("patch", route, handler, options); - const del = (route, options = {}, handler) => - insertRoute("delete", route, handler, options); - - // Modular Router - const registerRouter = (routerOpts) => { - const prefix = routerOpts.prefix; - const route = { - GET: (url, ...rest) => { - if (rest.length < 2 && typeof rest[0] !== "function") - throw new Error("varArgs : no callbacks specified"); - - insertRoute( - "get", - `${prefix ? "/" + prefix + url : url + "/"}`, - rest.length === 2 ? rest[0] : null, - rest.length === 1 ? rest[0] : rest[1] - ); - }, - POST: (url, ...rest) => { - if (rest.length < 2 && typeof rest[0] !== "function") - throw new Error("varArgs : no callbacks specified"); - - insertRoute( - "post", - `${prefix ? "/" + prefix + url : url + "/"}`, - rest.length === 2 ? rest[0] : null, - rest.length === 1 ? rest[0] : rest[1] - ); - }, - PUT: (url, ...rest) => { - if (rest.length < 2 && typeof rest[0] !== "function") - throw new Error("varArgs : no callbacks specified"); - - insertRoute( - "put", - `${prefix ? "/" + prefix + url : url + "/"}`, - rest.length === 2 ? rest[0] : null, - rest.length === 1 ? rest[0] : rest[1] - ); - }, - PATCH: (url, ...rest) => { - if (rest.length < 2 && typeof rest[0] !== "function") - throw new Error("varArgs : no callbacks specified"); - - insertRoute( - "patch", - `${prefix ? "/" + prefix + url : url + "/"}`, - rest.length === 2 ? rest[0] : null, - rest.length === 1 ? rest[0] : rest[1] - ); - }, - DELETE: (url, ...rest) => { - if (rest.length < 2 && typeof rest[0] !== "function") - throw new Error("varArgs : no callbacks specified"); - - insertRoute( - "delete", - `${prefix ? "/" + prefix + url : url + "/"}`, - rest.length === 2 ? rest[0] : null, - rest.length === 1 ? rest[0] : rest[1] - ); - }, - }; - - routerOpts.router(route); - }; - - /** - * Register an array of routers for modular code. - * Accepts an array of routers - */ - const combineRouters = (routers) => { - routers.forEach((router) => { - registerRouter(router); - }); - }; - - const listen = async (port, cb) => { - http - .createServer(async (req, res) => { - await bodyParser(req); - - // Handling middlewares - await handleMiddlewares(middlewares, req, res, (err) => { - if (err) { - res.writeHead(500); - res.end("Something went wrong"); - } - }); - - // Handling routes - const method = req.method.toLowerCase(); - let url = req.url.toLowerCase(); - if (url.includes("?")) { - const path = url.split("?"); - url = path[0]; - req.query = queryParser(path[1]); - } - const route = findRoute(routes, method, url); - if (route) { - let status = 200; - req.params = route.params; - res.code = (statusCode) => { - status = statusCode; - return res; - }; - res.send = (ctx, contentType) => { - try { - // Auto converts to JSON if possible - ctx = JSON.stringify(ctx); - res.writeHead(status, { - "Content-Type": "application/json", - }); - } catch (error) { - res.writeHead(status, { - "Content-Type": contentType || "text/plain", - }); - } - res.end(ctx); - }; - - return route.handler(req, res); - } - res.writeHead(404, { - "Content-Type": "text/plain", - }); - res.end( - JSON.stringify({ - url: req.url, - method: req.method, - msg: "Route not found", - statusCode: 404, - }) - ); - return; - }) - .listen(port, (e) => { - if (e) return console.log(e); - console.log(`${new Date().toUTCString()}`); - console.log(`Server started running at port ${port}`); - cb && cb(e); - }); - }; - - if (options.port) { - listen(options.port, options.init); - } - - return { - middleware, - GET: get, - POST: post, - PUT: put, - PATCH: patch, - DELETE: del, - listen, - registerRouter, - combineRouters, - }; - }; - - return app; -})(); diff --git a/src/lib/middleware.js b/src/lib/middleware.js deleted file mode 100644 index 469e32d..0000000 --- a/src/lib/middleware.js +++ /dev/null @@ -1,12 +0,0 @@ -async function handleMiddlewares(middlewares, req, res, callback) { - let i = 0; - const next = async () => { - let fn = middlewares[i++]; - if (i <= middlewares.length) { - await fn(req, res, next); - } - }; - next(); -} - -module.exports = handleMiddlewares; diff --git a/src/lib/query-parser/index.js b/src/lib/query-parser/index.js deleted file mode 100644 index 9417fc2..0000000 --- a/src/lib/query-parser/index.js +++ /dev/null @@ -1,15 +0,0 @@ -const queryParser = (queryStr) => { - try { - const queries = queryStr.split("&"); - const queryObj = {}; - queries.forEach((query) => { - const obj = query.split("="); - queryObj[obj[0]] = obj[1]; - }); - return queryObj; - } catch (error) { - throw "Invalid query string"; - } -}; - -module.exports = queryParser; diff --git a/src/lib/route-parser/.jshintrc b/src/lib/route-parser/.jshintrc deleted file mode 100644 index 6f8cc09..0000000 --- a/src/lib/route-parser/.jshintrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "browser": true, - "node": true, - "camelcase": true, - "eqeqeq": true, - "indent": 2, - "latedef": true, - "newcap": true, - "quotmark": "single", - "trailing": true, - "undef": true, - "unused": true, - "maxlen": 80, - "strict": true -} diff --git a/src/lib/route-parser/.npmignore b/src/lib/route-parser/.npmignore deleted file mode 100644 index 1ed04af..0000000 --- a/src/lib/route-parser/.npmignore +++ /dev/null @@ -1,19 +0,0 @@ -lib-cov -lcov.info -*.seed -*.log -*.csv -*.dat -*.out -*.pid -*.gz - -pids -logs -results -build -.grunt - -node_modules -coverage -docs diff --git a/src/lib/route-parser/.travis.yml b/src/lib/route-parser/.travis.yml deleted file mode 100644 index ede0214..0000000 --- a/src/lib/route-parser/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: node_js -node_js: - - "iojs" - - "0.12" - - "0.10" diff --git a/src/lib/route-parser/LICENSE.md b/src/lib/route-parser/LICENSE.md deleted file mode 100644 index 59e7847..0000000 --- a/src/lib/route-parser/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Ryan Sorensen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/src/lib/route-parser/README.md b/src/lib/route-parser/README.md deleted file mode 100644 index ee8d214..0000000 --- a/src/lib/route-parser/README.md +++ /dev/null @@ -1,81 +0,0 @@ -[![Build Status](https://travis-ci.org/rcs/route-parser.png?branch=master)](https://travis-ci.org/rcs/route-parser) -[![Dependency Status](https://david-dm.org/rcs/route-parser.svg?theme=shields.io)](https://david-dm.org/rcs/route-parser) -[![devDependency Status](https://david-dm.org/rcs/route-parser/dev-status.svg?theme=shields.io)](https://david-dm.org/rcs/route-parser#info=devDependencies) -## What is it? - -A isomorphic, bullet-proof, ninja-ready route parsing, matching, and reversing library for Javascript in Node and the browser. - -## Is it any good? - -Yes. - -## Why do I want it? - -You want to write routes in a way that makes sense, capture named parameters, add additional constraints to routing, and be able to generate links using your routes. You don't want to be surprised by limitations in your router or hit a spiral of additional complexity when you need to do more advanced tasks. - - -## How do I install it? - -```Shell -npm install --save route-parser -``` - -## How do I use it? - -```javascript -Route = require('route-parser'); -var route = new Route('/my/fancy/route/page/:page'); -route.match('/my/fancy/route/page/7') // { page: 7 } -route.reverse({page: 3}) // -> '/my/fancy/route/page/3' -``` -## What can I use in my routes? - -| Example | Description | -| --------------- | -------- | -| `:name` | a parameter to capture from the route up to `/`, `?`, or end of string | -| `*splat` | a splat to capture from the route up to `?` or end of string | -| `()` | Optional group that doesn't have to be part of the query. Can contain nested optional groups, params, and splats -| anything else | free form literals | - -Some examples: - -* `/some/(optional/):thing` -* `/users/:id/comments/:comment/rating/:rating` -* `/*a/foo/*b` -* `/books/*section/:title` -* `/books?author=:author&subject=:subject` - - -## How does it work? - -We define a grammar for route specifications and parse the route. Matching is done by generating a regular expression from that tree, and reversing is done by filling in parameter nodes in the tree. - - - - -## FAQ -### Isn't this over engineered? A full parser for route specifications? -Not really. Parsing route specs into regular expressions gets to be problematic if you want to do named captures and route reversing. Other routing libraries have issues with parsing one of `/foo(/:bar)` or `/foo(/:bar)`, and two-pass string-to-RegExp transforms become complex and error prone. - -Using a parser here also gives us the chance to give early feedback for any errors that are made in the route spec. - -### Why not use... - -#### [RFC 6570 URI Templates](http://tools.ietf.org/html/rfc6570) directly? - -URI templates are designed for expanding data into a template, not matching a route. Taking an arbitrary path and matching it against a URI template isn't defined. In the expansion step of URI templates, undefined variables can be evaluated to `''`, which isn't useful when trying to do route matching, optional or otherwise. To use a URI-template-like language is possible, but needs to be expanded past the RFC - -### [Express](http://expressjs.com/)/[Backbone.Router](http://backbonejs.org/docs/backbone.html#section-155)/[Director](https://github.com/flatiron/director) style routers - -These all lack named parameters and reversability. - -Named parameters are less brittle and reduce the coupling betwen routes and their handlers. Given the routes `/users/:userid/photos/:category` and `/photos/:category/users/:userid`, backbone style routing solutions require two different handlers. Named parameters let you use just one. - -Reversibility means you can use a single route table for your application for matching and generating links instead of throwing route helper functions throughout your code. - - -## Related - -* [rails/journey](http://github.com/rails/journey) -* [url-pattern](http://github.com/snd/url-pattern) -* [Director](https://github.com/flatiron/director) diff --git a/src/lib/route-parser/gulpfile.js b/src/lib/route-parser/gulpfile.js deleted file mode 100644 index e45ac4c..0000000 --- a/src/lib/route-parser/gulpfile.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict'; -var gulp = require('gulp'), - childProcess = require('child_process'), - jshint = require('gulp-jshint'); - - -var realCodePaths = [ - '**/*.{js,jsx,coffee}', - '!node_modules/**', - '!lib/route/compiled-grammar.js', - '!coverage/**', - '!docs/**' -]; - -gulp.task('lint', function() { - gulp.src(realCodePaths) - .pipe(jshint()) - .pipe(jshint.reporter('jshint-stylish')); -}); - -gulp.task('jsdoc', function() { - childProcess.exec( - './node_modules/.bin/jsdoc -c jsdoc.json', - function(error,stdout,stderr) { - console.log(stdout); - console.error(stderr); - } - ); -}); - -gulp.task('default',function() { - gulp.watch(realCodePaths, ['lint','jsdoc']); -}); - diff --git a/src/lib/route-parser/index.js b/src/lib/route-parser/index.js deleted file mode 100644 index 23274bd..0000000 --- a/src/lib/route-parser/index.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @module Passage - */ -'use strict'; - -var Route = require('./lib/route'); - - -module.exports = Route; \ No newline at end of file diff --git a/src/lib/route-parser/jsdoc.json b/src/lib/route-parser/jsdoc.json deleted file mode 100644 index 44dd6bb..0000000 --- a/src/lib/route-parser/jsdoc.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "source": { - "include": ["lib", "index.js"], - "exclude": ["./lib/route/compiled-grammar.js"] - }, - "opts": { - "destination": "./docs/", - "recurse": true, - "private": true - } -} - diff --git a/src/lib/route-parser/karma.conf.js b/src/lib/route-parser/karma.conf.js deleted file mode 100644 index d3c2224..0000000 --- a/src/lib/route-parser/karma.conf.js +++ /dev/null @@ -1,96 +0,0 @@ -/*jshint maxlen:120 */ -// Karma configuration -// Generated on Sat Feb 15 2014 18:21:16 GMT-0800 (PST) -'use strict'; - -module.exports = function(config) { - config.set({ - - // base path, that will be used to resolve files and exclude - basePath: '', - - - // frameworks to use - frameworks: ['mocha'], - - - // list of files / patterns to load in the browser - files: [ - 'node_modules/es5-shim/es5-shim.js', - 'test/**/*.js' - ], - - - // list of files to exclude - exclude: [ - ], - - - // test results reporter to use - // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' - reporters: ['progress'], - preprocessors: { - '**/*.js': ['webpack'] - }, - - - webpack: { - cache: true, - module: { - loaders: [ - // { test: /\.coffee$/, loader: 'coffee-loader' } - ] - } - }, - - webpackServer: { - stats: { - colors: true - } - }, - - - - // web server port - port: 9876, - - - // enable / disable colors in the output (reporters and logs) - colors: true, - - - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_DEBUG, - - - // enable / disable watching file and executing tests whenever any file changes - autoWatch: true, - - - // Start these browsers, currently available: - // - Chrome - // - ChromeCanary - // - Firefox - // - Opera (has to be installed with `npm install karma-opera-launcher`) - // - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`) - // - PhantomJS - // - IE (only Windows; has to be installed with `npm install karma-ie-launcher`) - browsers: ['PhantomJS'], - - - // If browser does not capture in given timeout [ms], kill it - captureTimeout: 60000, - - - // Continuous Integration mode - // if true, it capture browsers, run tests and exit - singleRun: false, - - plugins: [ - 'karma-webpack', - 'karma-mocha', - 'karma-phantomjs-launcher' - ] - }); -}; diff --git a/src/lib/route-parser/lib/route.js b/src/lib/route-parser/lib/route.js deleted file mode 100644 index 7ef1ef3..0000000 --- a/src/lib/route-parser/lib/route.js +++ /dev/null @@ -1,70 +0,0 @@ -'use strict'; -var Parser = require('./route/parser'), - RegexpVisitor = require('./route/visitors/regexp'), - ReverseVisitor = require('./route/visitors/reverse'); - -Route.prototype = Object.create(null) - -/** - * Match a path against this route, returning the matched parameters if - * it matches, false if not. - * @example - * var route = new Route('/this/is/my/route') - * route.match('/this/is/my/route') // -> {} - * @example - * var route = new Route('/:one/:two') - * route.match('/foo/bar/') // -> {one: 'foo', two: 'bar'} - * @param {string} path the path to match this route against - * @return {(Object.|false)} A map of the matched route - * parameters, or false if matching failed - */ -Route.prototype.match = function(path) { - var re = RegexpVisitor.visit(this.ast), - matched = re.match(path); - - return matched ? matched : false; - -}; - -/** - * Reverse a route specification to a path, returning false if it can't be - * fulfilled - * @example - * var route = new Route('/:one/:two') - * route.reverse({one: 'foo', two: 'bar'}) -> '/foo/bar' - * @param {Object} params The parameters to fill in - * @return {(String|false)} The filled in path - */ -Route.prototype.reverse = function(params) { - return ReverseVisitor.visit(this.ast, params); -}; - -/** - * Represents a route - * @example - * var route = Route('/:foo/:bar'); - * @example - * var route = Route('/:foo/:bar'); - * @param {string} spec - the string specification of the route. - * use :param for single portion captures, *param for splat style captures, - * and () for optional route branches - * @constructor - */ -function Route(spec) { - var route; - if (this) { - // constructor called with new - route = this; - } else { - // constructor called as a function - route = Object.create(Route.prototype); - } - if( typeof spec === 'undefined' ) { - throw new Error('A route spec is required'); - } - route.spec = spec; - route.ast = Parser.parse(spec); - return route; -} - -module.exports = Route; \ No newline at end of file diff --git a/src/lib/route-parser/lib/route/compiled-grammar.js b/src/lib/route-parser/lib/route/compiled-grammar.js deleted file mode 100644 index 58e6c01..0000000 --- a/src/lib/route-parser/lib/route/compiled-grammar.js +++ /dev/null @@ -1,632 +0,0 @@ -/* parser generated by jison 0.4.17 */ -/* - Returns a Parser object of the following structure: - - Parser: { - yy: {} - } - - Parser.prototype: { - yy: {}, - trace: function(), - symbols_: {associative list: name ==> number}, - terminals_: {associative list: number ==> name}, - productions_: [...], - performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), - table: [...], - defaultActions: {...}, - parseError: function(str, hash), - parse: function(input), - - lexer: { - EOF: 1, - parseError: function(str, hash), - setInput: function(input), - input: function(), - unput: function(str), - more: function(), - less: function(n), - pastInput: function(), - upcomingInput: function(), - showPosition: function(), - test_match: function(regex_match_array, rule_index), - next: function(), - lex: function(), - begin: function(condition), - popState: function(), - _currentRules: function(), - topState: function(), - pushState: function(condition), - - options: { - ranges: boolean (optional: true ==> token location info will include a .range[] member) - flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) - backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) - }, - - performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), - rules: [...], - conditions: {associative list: name ==> set}, - } - } - - - token location info (@$, _$, etc.): { - first_line: n, - last_line: n, - first_column: n, - last_column: n, - range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) - } - - - the parseError function receives a 'hash' object with these members for lexer and parser errors: { - text: (matched text) - token: (the produced terminal token, if any) - line: (yylineno) - } - while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { - loc: (yylloc) - expected: (string describing the set of expected tokens) - recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) - } -*/ -var parser = (function(){ -var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,9],$V1=[1,10],$V2=[1,11],$V3=[1,12],$V4=[5,11,12,13,14,15]; -var parser = {trace: function trace() { }, -yy: {}, -symbols_: {"error":2,"root":3,"expressions":4,"EOF":5,"expression":6,"optional":7,"literal":8,"splat":9,"param":10,"(":11,")":12,"LITERAL":13,"SPLAT":14,"PARAM":15,"$accept":0,"$end":1}, -terminals_: {2:"error",5:"EOF",11:"(",12:")",13:"LITERAL",14:"SPLAT",15:"PARAM"}, -productions_: [0,[3,2],[3,1],[4,2],[4,1],[6,1],[6,1],[6,1],[6,1],[7,3],[8,1],[9,1],[10,1]], -performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { -/* this == yyval */ - -var $0 = $$.length - 1; -switch (yystate) { -case 1: -return new yy.Root({},[$$[$0-1]]) -break; -case 2: -return new yy.Root({},[new yy.Literal({value: ''})]) -break; -case 3: -this.$ = new yy.Concat({},[$$[$0-1],$$[$0]]); -break; -case 4: case 5: -this.$ = $$[$0]; -break; -case 6: -this.$ = new yy.Literal({value: $$[$0]}); -break; -case 7: -this.$ = new yy.Splat({name: $$[$0]}); -break; -case 8: -this.$ = new yy.Param({name: $$[$0]}); -break; -case 9: -this.$ = new yy.Optional({},[$$[$0-1]]); -break; -case 10: -this.$ = yytext; -break; -case 11: case 12: -this.$ = yytext.slice(1); -break; -} -}, -table: [{3:1,4:2,5:[1,3],6:4,7:5,8:6,9:7,10:8,11:$V0,13:$V1,14:$V2,15:$V3},{1:[3]},{5:[1,13],6:14,7:5,8:6,9:7,10:8,11:$V0,13:$V1,14:$V2,15:$V3},{1:[2,2]},o($V4,[2,4]),o($V4,[2,5]),o($V4,[2,6]),o($V4,[2,7]),o($V4,[2,8]),{4:15,6:4,7:5,8:6,9:7,10:8,11:$V0,13:$V1,14:$V2,15:$V3},o($V4,[2,10]),o($V4,[2,11]),o($V4,[2,12]),{1:[2,1]},o($V4,[2,3]),{6:14,7:5,8:6,9:7,10:8,11:$V0,12:[1,16],13:$V1,14:$V2,15:$V3},o($V4,[2,9])], -defaultActions: {3:[2,2],13:[2,1]}, -parseError: function parseError(str, hash) { - if (hash.recoverable) { - this.trace(str); - } else { - function _parseError (msg, hash) { - this.message = msg; - this.hash = hash; - } - _parseError.prototype = Error; - - throw new _parseError(str, hash); - } -}, -parse: function parse(input) { - var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; - var args = lstack.slice.call(arguments, 1); - var lexer = Object.create(this.lexer); - var sharedState = { yy: {} }; - for (var k in this.yy) { - if (Object.prototype.hasOwnProperty.call(this.yy, k)) { - sharedState.yy[k] = this.yy[k]; - } - } - lexer.setInput(input, sharedState.yy); - sharedState.yy.lexer = lexer; - sharedState.yy.parser = this; - if (typeof lexer.yylloc == 'undefined') { - lexer.yylloc = {}; - } - var yyloc = lexer.yylloc; - lstack.push(yyloc); - var ranges = lexer.options && lexer.options.ranges; - if (typeof sharedState.yy.parseError === 'function') { - this.parseError = sharedState.yy.parseError; - } else { - this.parseError = Object.getPrototypeOf(this).parseError; - } - function popStack(n) { - stack.length = stack.length - 2 * n; - vstack.length = vstack.length - n; - lstack.length = lstack.length - n; - } - _token_stack: - var lex = function () { - var token; - token = lexer.lex() || EOF; - if (typeof token !== 'number') { - token = self.symbols_[token] || token; - } - return token; - }; - var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; - while (true) { - state = stack[stack.length - 1]; - if (this.defaultActions[state]) { - action = this.defaultActions[state]; - } else { - if (symbol === null || typeof symbol == 'undefined') { - symbol = lex(); - } - action = table[state] && table[state][symbol]; - } - if (typeof action === 'undefined' || !action.length || !action[0]) { - var errStr = ''; - expected = []; - for (p in table[state]) { - if (this.terminals_[p] && p > TERROR) { - expected.push('\'' + this.terminals_[p] + '\''); - } - } - if (lexer.showPosition) { - errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; - } else { - errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); - } - this.parseError(errStr, { - text: lexer.match, - token: this.terminals_[symbol] || symbol, - line: lexer.yylineno, - loc: yyloc, - expected: expected - }); - } - if (action[0] instanceof Array && action.length > 1) { - throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol); - } - switch (action[0]) { - case 1: - stack.push(symbol); - vstack.push(lexer.yytext); - lstack.push(lexer.yylloc); - stack.push(action[1]); - symbol = null; - if (!preErrorSymbol) { - yyleng = lexer.yyleng; - yytext = lexer.yytext; - yylineno = lexer.yylineno; - yyloc = lexer.yylloc; - if (recovering > 0) { - recovering--; - } - } else { - symbol = preErrorSymbol; - preErrorSymbol = null; - } - break; - case 2: - len = this.productions_[action[1]][1]; - yyval.$ = vstack[vstack.length - len]; - yyval._$ = { - first_line: lstack[lstack.length - (len || 1)].first_line, - last_line: lstack[lstack.length - 1].last_line, - first_column: lstack[lstack.length - (len || 1)].first_column, - last_column: lstack[lstack.length - 1].last_column - }; - if (ranges) { - yyval._$.range = [ - lstack[lstack.length - (len || 1)].range[0], - lstack[lstack.length - 1].range[1] - ]; - } - r = this.performAction.apply(yyval, [ - yytext, - yyleng, - yylineno, - sharedState.yy, - action[1], - vstack, - lstack - ].concat(args)); - if (typeof r !== 'undefined') { - return r; - } - if (len) { - stack = stack.slice(0, -1 * len * 2); - vstack = vstack.slice(0, -1 * len); - lstack = lstack.slice(0, -1 * len); - } - stack.push(this.productions_[action[1]][0]); - vstack.push(yyval.$); - lstack.push(yyval._$); - newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; - stack.push(newState); - break; - case 3: - return true; - } - } - return true; -}}; -/* generated by jison-lex 0.3.4 */ -var lexer = (function(){ -var lexer = ({ - -EOF:1, - -parseError:function parseError(str, hash) { - if (this.yy.parser) { - this.yy.parser.parseError(str, hash); - } else { - throw new Error(str); - } - }, - -// resets the lexer, sets new input -setInput:function (input, yy) { - this.yy = yy || this.yy || {}; - this._input = input; - this._more = this._backtrack = this.done = false; - this.yylineno = this.yyleng = 0; - this.yytext = this.matched = this.match = ''; - this.conditionStack = ['INITIAL']; - this.yylloc = { - first_line: 1, - first_column: 0, - last_line: 1, - last_column: 0 - }; - if (this.options.ranges) { - this.yylloc.range = [0,0]; - } - this.offset = 0; - return this; - }, - -// consumes and returns one char from the input -input:function () { - var ch = this._input[0]; - this.yytext += ch; - this.yyleng++; - this.offset++; - this.match += ch; - this.matched += ch; - var lines = ch.match(/(?:\r\n?|\n).*/g); - if (lines) { - this.yylineno++; - this.yylloc.last_line++; - } else { - this.yylloc.last_column++; - } - if (this.options.ranges) { - this.yylloc.range[1]++; - } - - this._input = this._input.slice(1); - return ch; - }, - -// unshifts one char (or a string) into the input -unput:function (ch) { - var len = ch.length; - var lines = ch.split(/(?:\r\n?|\n)/g); - - this._input = ch + this._input; - this.yytext = this.yytext.substr(0, this.yytext.length - len); - //this.yyleng -= len; - this.offset -= len; - var oldLines = this.match.split(/(?:\r\n?|\n)/g); - this.match = this.match.substr(0, this.match.length - 1); - this.matched = this.matched.substr(0, this.matched.length - 1); - - if (lines.length - 1) { - this.yylineno -= lines.length - 1; - } - var r = this.yylloc.range; - - this.yylloc = { - first_line: this.yylloc.first_line, - last_line: this.yylineno + 1, - first_column: this.yylloc.first_column, - last_column: lines ? - (lines.length === oldLines.length ? this.yylloc.first_column : 0) - + oldLines[oldLines.length - lines.length].length - lines[0].length : - this.yylloc.first_column - len - }; - - if (this.options.ranges) { - this.yylloc.range = [r[0], r[0] + this.yyleng - len]; - } - this.yyleng = this.yytext.length; - return this; - }, - -// When called from action, caches matched text and appends it on next action -more:function () { - this._more = true; - return this; - }, - -// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead. -reject:function () { - if (this.options.backtrack_lexer) { - this._backtrack = true; - } else { - return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), { - text: "", - token: null, - line: this.yylineno - }); - - } - return this; - }, - -// retain first n characters of the match -less:function (n) { - this.unput(this.match.slice(n)); - }, - -// displays already matched input, i.e. for error messages -pastInput:function () { - var past = this.matched.substr(0, this.matched.length - this.match.length); - return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); - }, - -// displays upcoming input, i.e. for error messages -upcomingInput:function () { - var next = this.match; - if (next.length < 20) { - next += this._input.substr(0, 20-next.length); - } - return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); - }, - -// displays the character position where the lexing error occurred, i.e. for error messages -showPosition:function () { - var pre = this.pastInput(); - var c = new Array(pre.length + 1).join("-"); - return pre + this.upcomingInput() + "\n" + c + "^"; - }, - -// test the lexed token: return FALSE when not a match, otherwise return token -test_match:function (match, indexed_rule) { - var token, - lines, - backup; - - if (this.options.backtrack_lexer) { - // save context - backup = { - yylineno: this.yylineno, - yylloc: { - first_line: this.yylloc.first_line, - last_line: this.last_line, - first_column: this.yylloc.first_column, - last_column: this.yylloc.last_column - }, - yytext: this.yytext, - match: this.match, - matches: this.matches, - matched: this.matched, - yyleng: this.yyleng, - offset: this.offset, - _more: this._more, - _input: this._input, - yy: this.yy, - conditionStack: this.conditionStack.slice(0), - done: this.done - }; - if (this.options.ranges) { - backup.yylloc.range = this.yylloc.range.slice(0); - } - } - - lines = match[0].match(/(?:\r\n?|\n).*/g); - if (lines) { - this.yylineno += lines.length; - } - this.yylloc = { - first_line: this.yylloc.last_line, - last_line: this.yylineno + 1, - first_column: this.yylloc.last_column, - last_column: lines ? - lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : - this.yylloc.last_column + match[0].length - }; - this.yytext += match[0]; - this.match += match[0]; - this.matches = match; - this.yyleng = this.yytext.length; - if (this.options.ranges) { - this.yylloc.range = [this.offset, this.offset += this.yyleng]; - } - this._more = false; - this._backtrack = false; - this._input = this._input.slice(match[0].length); - this.matched += match[0]; - token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]); - if (this.done && this._input) { - this.done = false; - } - if (token) { - return token; - } else if (this._backtrack) { - // recover context - for (var k in backup) { - this[k] = backup[k]; - } - return false; // rule action called reject() implying the next rule should be tested instead. - } - return false; - }, - -// return next match in input -next:function () { - if (this.done) { - return this.EOF; - } - if (!this._input) { - this.done = true; - } - - var token, - match, - tempMatch, - index; - if (!this._more) { - this.yytext = ''; - this.match = ''; - } - var rules = this._currentRules(); - for (var i = 0; i < rules.length; i++) { - tempMatch = this._input.match(this.rules[rules[i]]); - if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { - match = tempMatch; - index = i; - if (this.options.backtrack_lexer) { - token = this.test_match(tempMatch, rules[i]); - if (token !== false) { - return token; - } else if (this._backtrack) { - match = false; - continue; // rule action called reject() implying a rule MISmatch. - } else { - // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) - return false; - } - } else if (!this.options.flex) { - break; - } - } - } - if (match) { - token = this.test_match(match, rules[index]); - if (token !== false) { - return token; - } - // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) - return false; - } - if (this._input === "") { - return this.EOF; - } else { - return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { - text: "", - token: null, - line: this.yylineno - }); - } - }, - -// return next match that has a token -lex:function lex() { - var r = this.next(); - if (r) { - return r; - } else { - return this.lex(); - } - }, - -// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack) -begin:function begin(condition) { - this.conditionStack.push(condition); - }, - -// pop the previously active lexer condition state off the condition stack -popState:function popState() { - var n = this.conditionStack.length - 1; - if (n > 0) { - return this.conditionStack.pop(); - } else { - return this.conditionStack[0]; - } - }, - -// produce the lexer rule set which is active for the currently active lexer condition state -_currentRules:function _currentRules() { - if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) { - return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; - } else { - return this.conditions["INITIAL"].rules; - } - }, - -// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available -topState:function topState(n) { - n = this.conditionStack.length - 1 - Math.abs(n || 0); - if (n >= 0) { - return this.conditionStack[n]; - } else { - return "INITIAL"; - } - }, - -// alias for begin(condition) -pushState:function pushState(condition) { - this.begin(condition); - }, - -// return the number of states currently on the stack -stateStackSize:function stateStackSize() { - return this.conditionStack.length; - }, -options: {}, -performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { -var YYSTATE=YY_START; -switch($avoiding_name_collisions) { -case 0:return "("; -break; -case 1:return ")"; -break; -case 2:return "SPLAT"; -break; -case 3:return "PARAM"; -break; -case 4:return "LITERAL"; -break; -case 5:return "LITERAL"; -break; -case 6:return "EOF"; -break; -} -}, -rules: [/^(?:\()/,/^(?:\))/,/^(?:\*+\w+)/,/^(?::+\w+)/,/^(?:[\w%\-~\n]+)/,/^(?:.)/,/^(?:$)/], -conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6],"inclusive":true}} -}); -return lexer; -})(); -parser.lexer = lexer; -function Parser () { - this.yy = {}; -} -Parser.prototype = parser;parser.Parser = Parser; -return new Parser; -})(); - - -if (typeof require !== 'undefined' && typeof exports !== 'undefined') { -exports.parser = parser; -exports.Parser = parser.Parser; -exports.parse = function () { return parser.parse.apply(parser, arguments); }; -} \ No newline at end of file diff --git a/src/lib/route-parser/lib/route/grammar.js b/src/lib/route-parser/lib/route/grammar.js deleted file mode 100644 index 29503cd..0000000 --- a/src/lib/route-parser/lib/route/grammar.js +++ /dev/null @@ -1,73 +0,0 @@ -/** @module route/grammar */ -'use strict'; - -/** - * Helper for jison grammar definitions, altering "new" calls to the - * yy namepsace and assigning action results to "$$" - * @example - * o('foo', 'new Lllama($1)') // -> ['foo', '$$ = new yy.Llama($1)'] - * @param {String} patternString a jison BNF pattern string - * @param {String} action the javascript code to execute against the pattern - * @return {Array.} the expression strings to give to jison - * @private - */ -function o(patternString, action) { - if( typeof action === 'undefined') { - return [patternString, '$$ = $1;']; - } - else { - action = action.replace(/\bnew /g, '$&yy.'); - return [patternString, '$$ = ' + action + ';']; - } - -} - - -module.exports = { - 'lex': { - 'rules': [ - ['\\(', 'return "(";' ], - ['\\)', 'return ")";' ], - ['\\*+\\w+', 'return "SPLAT";' ], - [':+\\w+', 'return "PARAM";' ], - ['[\\w%\\-~\\n]+', 'return "LITERAL";' ], - ['.', 'return "LITERAL";' ], - ['$', 'return "EOF";' ] - ] - }, - 'bnf': { - 'root': [ - ['expressions EOF', 'return new yy.Root({},[$1])'], - ['EOF', 'return new yy.Root({},[new yy.Literal({value: \'\'})])'] - ], - 'expressions': [ - o('expressions expression', 'new Concat({},[$1,$2])'), - o('expression') - ], - 'expression': [ - o('optional'), - o('literal', 'new Literal({value: $1})'), - o('splat', 'new Splat({name: $1})'), - o('param', 'new Param({name: $1})') - ], - 'optional': [ - o('( expressions )', 'new Optional({},[$2])') - ], - 'literal': [ - o('LITERAL', 'yytext') - ], - 'splat': [ - o('SPLAT', 'yytext.slice(1)') - ], - 'param': [ - o('PARAM', 'yytext.slice(1)') - ] - }, - 'startSymbol': 'root' -}; - - -//var parser = new (require('jison').Parser)(grammar); -//parser.yy = require('./nodes'); - -//module.exports = parser; diff --git a/src/lib/route-parser/lib/route/nodes.js b/src/lib/route-parser/lib/route/nodes.js deleted file mode 100644 index 6bb4215..0000000 --- a/src/lib/route-parser/lib/route/nodes.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; -/** @module route/nodes */ - - -/** - * Create a node for use with the parser, giving it a constructor that takes - * props, children, and returns an object with props, children, and a - * displayName. - * @param {String} displayName The display name for the node - * @return {{displayName: string, props: Object, children: Array}} - */ -function createNode(displayName) { - return function(props, children) { - return { - displayName: displayName, - props: props, - children: children || [] - }; - }; -} - -module.exports = { - Root: createNode('Root'), - Concat: createNode('Concat'), - Literal: createNode('Literal'), - Splat: createNode('Splat'), - Param: createNode('Param'), - Optional: createNode('Optional') -}; diff --git a/src/lib/route-parser/lib/route/parser.js b/src/lib/route-parser/lib/route/parser.js deleted file mode 100644 index 8732749..0000000 --- a/src/lib/route-parser/lib/route/parser.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @module route/parser - */ -'use strict'; - -/** Wrap the compiled parser with the context to create node objects */ -var parser = require('./compiled-grammar').parser; -parser.yy = require('./nodes'); -module.exports = parser; diff --git a/src/lib/route-parser/lib/route/visitors/create_visitor.js b/src/lib/route-parser/lib/route/visitors/create_visitor.js deleted file mode 100644 index a56a2c3..0000000 --- a/src/lib/route-parser/lib/route/visitors/create_visitor.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; -/** - * @module route/visitors/create_visitor - */ - -var nodeTypes = Object.keys(require('../nodes')); - -/** - * Helper for creating visitors. Take an object of node name to handler - * mappings, returns an object with a "visit" method that can be called - * @param {Object.} handlers A mapping of node - * type to visitor functions - * @return {{visit: function(node,context)}} A visitor object with a "visit" - * method that can be called on a node with a context - */ -function createVisitor(handlers) { - nodeTypes.forEach(function(nodeType) { - if( typeof handlers[nodeType] === 'undefined') { - throw new Error('No handler defined for ' + nodeType.displayName); - } - - }); - - return { - /** - * Call the given handler for this node type - * @param {Object} node the AST node - * @param {Object} context context to pass through to handlers - * @return {Object} - */ - visit: function(node, context) { - return this.handlers[node.displayName].call(this,node, context); - }, - handlers: handlers - }; -} - -module.exports = createVisitor; \ No newline at end of file diff --git a/src/lib/route-parser/lib/route/visitors/reconstruct.js b/src/lib/route-parser/lib/route/visitors/reconstruct.js deleted file mode 100644 index 0bdb22f..0000000 --- a/src/lib/route-parser/lib/route/visitors/reconstruct.js +++ /dev/null @@ -1,40 +0,0 @@ -'use strict'; - -var createVisitor = require('./create_visitor'); - -/** - * Visitor for the AST to reconstruct the normalized input - * @class ReconstructVisitor - * @borrows Visitor-visit - */ -var ReconstructVisitor = createVisitor({ - 'Concat': function(node) { - return node.children - .map( function(child) { - return this.visit(child); - }.bind(this)) - .join(''); - }, - - 'Literal': function(node) { - return node.props.value; - }, - - 'Splat': function(node) { - return '*' + node.props.name; - }, - - 'Param': function(node) { - return ':' + node.props.name; - }, - - 'Optional': function(node) { - return '(' + this.visit(node.children[0]) + ')'; - }, - - 'Root': function(node) { - return this.visit(node.children[0]); - } -}); - -module.exports = ReconstructVisitor; \ No newline at end of file diff --git a/src/lib/route-parser/lib/route/visitors/regexp.js b/src/lib/route-parser/lib/route/visitors/regexp.js deleted file mode 100644 index 1b7a938..0000000 --- a/src/lib/route-parser/lib/route/visitors/regexp.js +++ /dev/null @@ -1,97 +0,0 @@ -'use strict'; - -var createVisitor = require('./create_visitor'), - escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; - -/** - * @class - * @private - */ -function Matcher(options) { - this.captures = options.captures; - this.re = options.re; -} - -/** - * Try matching a path against the generated regular expression - * @param {String} path The path to try to match - * @return {Object|false} matched parameters or false - */ -Matcher.prototype.match = function (path) { - var match = this.re.exec(path), - matchParams = {}; - - if( !match ) { - return; - } - - this.captures.forEach( function(capture, i) { - if( typeof match[i+1] === 'undefined' ) { - matchParams[capture] = undefined; - } - else { - matchParams[capture] = decodeURIComponent(match[i+1]); - } - }); - - return matchParams; -}; - -/** - * Visitor for the AST to create a regular expression matcher - * @class RegexpVisitor - * @borrows Visitor-visit - */ -var RegexpVisitor = createVisitor({ - 'Concat': function(node) { - return node.children - .reduce( - function(memo, child) { - var childResult = this.visit(child); - return { - re: memo.re + childResult.re, - captures: memo.captures.concat(childResult.captures) - }; - }.bind(this), - {re: '', captures: []} - ); - }, - 'Literal': function(node) { - return { - re: node.props.value.replace(escapeRegExp, '\\$&'), - captures: [] - }; - }, - - 'Splat': function(node) { - return { - re: '([^?]*?)', - captures: [node.props.name] - }; - }, - - 'Param': function(node) { - return { - re: '([^\\/\\?]+)', - captures: [node.props.name] - }; - }, - - 'Optional': function(node) { - var child = this.visit(node.children[0]); - return { - re: '(?:' + child.re + ')?', - captures: child.captures - }; - }, - - 'Root': function(node) { - var childResult = this.visit(node.children[0]); - return new Matcher({ - re: new RegExp('^' + childResult.re + '(?=\\?|$)' ), - captures: childResult.captures - }); - } -}); - -module.exports = RegexpVisitor; \ No newline at end of file diff --git a/src/lib/route-parser/lib/route/visitors/reverse.js b/src/lib/route-parser/lib/route/visitors/reverse.js deleted file mode 100644 index 9cdd5e1..0000000 --- a/src/lib/route-parser/lib/route/visitors/reverse.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - -var createVisitor = require('./create_visitor'); - -/** - * Visitor for the AST to construct a path with filled in parameters - * @class ReverseVisitor - * @borrows Visitor-visit - */ -var ReverseVisitor = createVisitor({ - 'Concat': function(node, context) { - var childResults = node.children - .map( function(child) { - return this.visit(child,context); - }.bind(this)); - - if( childResults.some(function(c) { return c === false; }) ) { - return false; - } - else { - return childResults.join(''); - } - }, - - 'Literal': function(node) { - return decodeURI(node.props.value); - }, - - 'Splat': function(node, context) { - if( context[node.props.name] ) { - return context[node.props.name]; - } - else { - return false; - } - }, - - 'Param': function(node, context) { - if( context[node.props.name] ) { - return context[node.props.name]; - } - else { - return false; - } - }, - - 'Optional': function(node, context) { - var childResult = this.visit(node.children[0], context); - if( childResult ) { - return childResult; - } - else { - return ''; - } - }, - - 'Root': function(node, context) { - context = context || {}; - var childResult = this.visit(node.children[0], context); - if( !childResult ) { - return false; - } - return encodeURI(childResult); - } -}); - -module.exports = ReverseVisitor; \ No newline at end of file diff --git a/src/lib/route-parser/package.json b/src/lib/route-parser/package.json deleted file mode 100644 index 58a6579..0000000 --- a/src/lib/route-parser/package.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "_from": "route-parser", - "_id": "route-parser@0.0.5", - "_inBundle": false, - "_integrity": "sha1-fR0J0zXkkJQDHqFpkaSnmwG74fQ=", - "_location": "/route-parser", - "_phantomChildren": {}, - "_requested": { - "type": "tag", - "registry": true, - "raw": "route-parser", - "name": "route-parser", - "escapedName": "route-parser", - "rawSpec": "", - "saveSpec": null, - "fetchSpec": "latest" - }, - "_requiredBy": [ - "#USER", - "/" - ], - "_resolved": "https://registry.npmjs.org/route-parser/-/route-parser-0.0.5.tgz", - "_shasum": "7d1d09d335e49094031ea16991a4a79b01bbe1f4", - "_spec": "route-parser", - "_where": "D:\\FROM DRIVE D\\Projects\\node-http-framework", - "author": { - "name": "Ryan Sorensen", - "email": "rcsorensen@gmail.com", - "url": "https://github.com/rcs" - }, - "bugs": { - "url": "http://github.com/rcs/route-parser/issues", - "email": "rcsorensen@gmail.com" - }, - "bundleDependencies": false, - "deprecated": false, - "description": "A isomorphic, bullet-proof, ninja-ready route parsing, matching, and reversing library for Javascript in Node and the browser. ", - "devDependencies": { - "chai": "~3.2.0", - "es5-shim": "~4.1.10", - "gulp": "~3.9.0", - "gulp-exec": "~1.0.4", - "gulp-jshint": "~1.11.2", - "jison": "~0.4.17", - "jison-lex": "~0.3.4", - "jsdoc": "~3.3.0-alpha4", - "jshint-stylish": "~0.1.5", - "karma": "~0.12.36", - "karma-mocha": "~0.1.1", - "karma-phantomjs-launcher": "~0.2.0", - "karma-webpack": "~1.6.0", - "mocha": "~2.2.5", - "webpack": "~1.10.5", - "webpack-dev-server": "~1.10.1" - }, - "directories": { - "test": "test" - }, - "engines": { - "node": ">= 0.9" - }, - "homepage": "http://github.com/rcs/route-parser", - "keywords": [ - "url", - "matching", - "routing", - "route", - "regex", - "match" - ], - "license": "MIT", - "main": "index.js", - "name": "route-parser", - "repository": { - "type": "git", - "url": "git+https://github.com/rcs/route-parser.git" - }, - "scripts": { - "clean-compile": "rm ./lib/route/compiled-grammar.js", - "compile-parser": "scripts/compile_parser.js", - "test": "mocha && karma start --singleRun", - "test-client": "karma start --singleRun", - "test-node": "mocha" - }, - "version": "0.0.5" -} diff --git a/src/lib/route-parser/scripts/compile_parser.js b/src/lib/route-parser/scripts/compile_parser.js deleted file mode 100644 index 0e7bf91..0000000 --- a/src/lib/route-parser/scripts/compile_parser.js +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env node -var fs = require('fs'); - -var jison = require('jison'), - Lexer = require('jison-lex'), - grammar = require('../lib/route/grammar.js'), - parser = new jison.Parser(grammar); - -parser.lexer = new Lexer(grammar.lex, null, grammar.terminals_); - -var compiledGrammar = parser.generate({moduleType: 'js'}); - - -fs.writeFileSync( - __dirname + '/../lib/route/compiled-grammar.js', - [ - compiledGrammar, - "\n\n\nif (typeof require !== 'undefined' && typeof exports !== 'undefined') {", - "\nexports.parser = parser;", - "\nexports.Parser = parser.Parser;", - "\nexports.parse = function () { return parser.parse.apply(parser, arguments); };", - "\n}" - ].join('') -); diff --git a/src/lib/route-parser/test/backbone-compatibility.js b/src/lib/route-parser/test/backbone-compatibility.js deleted file mode 100644 index 3a0637e..0000000 --- a/src/lib/route-parser/test/backbone-compatibility.js +++ /dev/null @@ -1,166 +0,0 @@ -/*global describe, it */ -'use strict'; -var assert = require('chai').assert, - RouteParser = require('../lib/route'); - -/* Route, path, expected params, options {name, reversed} */ -var backboneTestCases = [ - [ - 'search/:query', - 'search/news', - {query: 'news'}, - {name: 'simple'} - ], - [ - 'search/:query', - 'search/тест', - {query: 'тест'}, - {name: 'simple with unicode', reversed: 'search/%D1%82%D0%B5%D1%81%D1%82'} - ], - [ - 'search/:query/p:page', - 'search/nyc/p10', - {query: 'nyc', page: '10'}, - {name: 'two part'} - ], - [ - 'splat/*args/end', - 'splat/long-list/of/splatted_99args/end', - {args: 'long-list/of/splatted_99args'}, - {name: 'splats'} - ], - [ - ':repo/compare/*from...*to', - 'backbone/compare/1.0...braddunbar:with/slash', - {repo: 'backbone', from: '1.0', to: 'braddunbar:with/slash'}, - {name: 'complicated mixed'} - ], - [ - 'optional(/:item)', - 'optional', - {item: undefined}, - {name: 'optional'} - ], - [ - 'optional(/:item)', - 'optional/thing', - {item: 'thing'}, - {name: 'optional with param'} - ], - [ - '*first/complex-*part/*rest', - 'one/two/three/complex-part/four/five/six/seven', - {first: 'one/two/three', part: 'part',rest: 'four/five/six/seven'}, - {name: 'complex'} - ], - [ - '*first/complex-*part/*rest', - 'has%2Fslash/complex-has%23hash/has%20space', - {first: 'has/slash', part: 'has#hash', rest: 'has space'}, - { - name: 'backbone#967 decodes encoded values', - reversed: 'has/slash/complex-has#hash/has%20space' - } - ], - [ - '*anything', - 'doesnt-match-a-route', - {anything: 'doesnt-match-a-route'}, - {name: 'anything'} - ], - [ - 'decode/:named/*splat', - 'decode/a%2Fb/c%2Fd/e', - {named: 'a/b', splat: 'c/d/e'}, - {name: 'decode named parameters, not splats', reversed: 'decode/a/b/c/d/e'} - ], - [ - 'charñ', - 'char%C3%B1', - false, - {name: '#2666 - Hashes with UTF8 in them.', reversed: 'char%C3%B1'} - ], - [ - 'charñ', - 'charñ', - {}, - {name: '#2666 - Hashes with UTF8 in them.', reversed: 'char%C3%B1'} - ], - [ - 'char%C3%B1', - 'charñ', - false, - {name: '#2666 - Hashes with UTF8 in them.', reversed: 'char%C3%B1'} - ], - [ - 'char%C3%B1', - 'char%C3%B1', - {}, - {name: '#2666 - Hashes with UTF8 in them.', reversed: 'char%C3%B1'} - ], - [ - '', - '', - {}, - {name: 'Allows empty route'} - ], - [ - 'named/optional/(y:z)', - 'named/optional/y', - false, - {name: 'doesn\'t match an unfulfilled optional route'} - ], - [ - 'some/(optional/):thing', - 'some/foo', - {thing: 'foo'}, - { - name: 'backbone#1980 optional with trailing slash', - reversed: 'some/optional/foo' - } - ], - [ - 'some/(optional/):thing', - 'some/optional/foo', - {thing: 'foo'}, - {name: 'backbone#1980 optional with trailing slash'} - ], - [ - 'myyjä', - 'myyjä', - {}, - {name: 'unicode pathname', reversed: 'myyj%C3%A4'} - ], - [ - 'stuff\nnonsense', - 'stuff\nnonsense?param=foo%0Abar', - {}, - {name: 'newline in route', reversed: 'stuff%0Anonsense'} - ] -].map( function(testCase) { - var routeSpec = testCase[0], - path = testCase[1], - captured = testCase[2], - name = testCase[3].name, - reversed = testCase[3].reversed || testCase[1]; - - return function() { - it(testCase[3].name, function() { - var route = new RouteParser(routeSpec); - assert.deepEqual(route.match(path), captured); - }); - /* Only reverse routes we expected to succeed */ - if( captured ) { - it( 'reverses ' + name, function() { - var route = RouteParser(routeSpec); - assert.equal(route.reverse(captured), reversed); - }); - } - }; -}); - -describe('Backbone route compatibility', function() { - for (var i = 0; i < backboneTestCases.length; i++) { - backboneTestCases[i](); - } -}); \ No newline at end of file diff --git a/src/lib/route-parser/test/test.js b/src/lib/route-parser/test/test.js deleted file mode 100644 index 317c38d..0000000 --- a/src/lib/route-parser/test/test.js +++ /dev/null @@ -1,159 +0,0 @@ -/*jslint maxlen: 130 */ -/*global describe, it */ - -'use strict'; -var assert = require('chai').assert, - RouteParser = require('../'); - - -describe('Route', function() { - it('should create', function() { - assert.ok(RouteParser('/foo')); - }); - - it('should create with new', function() { - assert.ok(new RouteParser('/foo')); - }); - - it('should have proper prototype', function() { - var routeInstance = new RouteParser('/foo') - assert.ok(routeInstance instanceof RouteParser); - }); - - it('should throw on no spec',function() { - assert.throw(function(){ RouteParser(); }, Error, /spec is required/); - }); - - describe('basic', function() { - it('should match /foo with a path of /foo', function() { - var route = RouteParser('/foo'); - assert.ok(route.match('/foo')); - }); - - it('should match /foo with a path of /foo?query',function() { - var route = RouteParser('/foo'); - assert.ok(route.match('/foo?query')); - }); - - it('shouldn\'t match /foo with a path of /bar/foo', function() { - var route = RouteParser('/foo'); - assert.notOk(route.match('/bar/foo')); - }); - - it('shouldn\'t match /foo with a path of /foobar', function() { - var route = RouteParser('/foo'); - assert.notOk(route.match('/foobar')); - }); - - it('shouldn\'t match /foo with a path of /bar', function() { - var route = RouteParser('/foo'); - assert.notOk(route.match('/bar')); - }); - }); - - describe('basic parameters', function() { - it('should match /users/:id with a path of /users/1', function() { - var route = RouteParser('/users/:id'); - assert.ok(route.match('/users/1')); - }); - - it('should not match /users/:id with a path of /users/', function() { - var route = RouteParser('/users/:id'); - assert.notOk(route.match('/users/')); - }); - - it('should match /users/:id with a path of /users/1 and get parameters', function() { - var route = RouteParser('/users/:id'); - assert.deepEqual(route.match('/users/1'), {id: '1'}); - }); - - it('should match deep pathing and get parameters', function() { - var route = RouteParser('/users/:id/comments/:comment/rating/:rating'); - assert.deepEqual(route.match('/users/1/comments/cats/rating/22222'), {id: '1', comment: 'cats', rating: '22222'}); - }); - }); - - describe('splat parameters', function() { - it('should handle double splat parameters', function() { - var route = RouteParser('/*a/foo/*b'); - assert.deepEqual(route.match('/zoo/woo/foo/bar/baz'), {a: 'zoo/woo', b: 'bar/baz'}); - }); - }); - - describe('mixed', function() { - it('should handle mixed splat and named parameters', function() { - var route = RouteParser('/books/*section/:title'); - assert.deepEqual( - route.match('/books/some/section/last-words-a-memoir'), - {section: 'some/section', title: 'last-words-a-memoir'} - ); - }); - }); - - describe('optional', function() { - it('should allow and match optional routes', function() { - var route = RouteParser('/users/:id(/style/:style)'); - assert.deepEqual(route.match('/users/3'), {id: '3', style: undefined}); - }); - - it('should allow and match optional routes', function() { - var route = RouteParser('/users/:id(/style/:style)'); - assert.deepEqual(route.match('/users/3/style/pirate'), {id: '3', style: 'pirate'}); - }); - - it('allows optional branches that start with a word character', function() { - var route = RouteParser('/things/(option/:first)'); - assert.deepEqual(route.match('/things/option/bar'), {first: 'bar'}); - }); - - describe('nested', function() { - it('allows nested', function() { - var route = RouteParser('/users/:id(/style/:style(/more/:param))'); - var result = route.match('/users/3/style/pirate'); - var expected = {id: '3', style: 'pirate', param: undefined}; - assert.deepEqual(result, expected); - }); - - it('fetches the correct params from nested', function() { - var route = RouteParser('/users/:id(/style/:style(/more/:param))'); - assert.deepEqual(route.match('/users/3/style/pirate/more/things'), {id: '3', style: 'pirate', param: 'things'}); - }); - }); - }); - - describe('reverse', function(){ - it('reverses routes without params', function() { - var route = RouteParser('/foo'); - assert.equal(route.reverse(),'/foo'); - }); - - it('reverses routes with simple params', function() { - var route = RouteParser('/:foo/:bar'); - assert.equal(route.reverse({foo: '1', bar: '2'}), '/1/2'); - }); - - it('reverses routes with optional params', function() { - var route = RouteParser('/things/(option/:first)'); - assert.equal(route.reverse({first: 'bar'}), '/things/option/bar'); - }); - - it('reverses routes with unfilled optional params', function() { - var route = RouteParser('/things/(option/:first)'); - assert.equal(route.reverse(), '/things/'); - }); - - it('reverses routes with optional params that can\'t fulfill the optional branch', function() { - var route = RouteParser('/things/(option/:first(/second/:second))'); - assert.equal(route.reverse({second: 'foo'}), '/things/'); - }); - - it('returns false for routes that can\'t be fulfilled', function() { - var route = RouteParser('/foo/:bar'); - assert.equal(route.reverse({}),false); - }); - it('returns false for routes with splat params that can\'t be fulfilled', function() { - var route = RouteParser('/foo/*bar'); - assert.equal(route.reverse({}),false); - }); - }); -}); diff --git a/src/lib/route-parser/test/visitor.js b/src/lib/route-parser/test/visitor.js deleted file mode 100644 index ab95d27..0000000 --- a/src/lib/route-parser/test/visitor.js +++ /dev/null @@ -1,42 +0,0 @@ -/*jslint maxlen: 130 */ -/*global describe, it */ - -'use strict'; -var assert = require('chai').assert, - createVisitor = require('../lib/route/visitors/create_visitor'); - -function sillyVisitor( node ) { - return node.displayName; -} - - -describe('createVisitor', function() { - it('should throw if not all handler node types are defined', function() { - assert.throw(function() { - createVisitor({Root: function(){}}); - }, - /No handler defined/ - ); - }); - - it('should create when all handlers are defined',function() { - var visitor = createVisitor({ - Root: function(node) { return 'Root(' + this.visit(node.children[0]) + ')'; }, - Concat: function(node) { - return 'Concat(' + node.children - .map( function(child) { - return this.visit(child); - }.bind(this)) - .join(' ') + ')'; - }, - Optional: function(node) { return 'Optional(' + this.visit(node.children[0]) + ')'; }, - Literal: sillyVisitor, - Splat: sillyVisitor, - Param: sillyVisitor - }); - - assert.ok(visitor); - - }); -}); - diff --git a/test/auth.route.js b/test/auth.route.js new file mode 100644 index 0000000..b1ea87a --- /dev/null +++ b/test/auth.route.js @@ -0,0 +1,8 @@ +module.exports = (router) => { + router.GET("/", (req, res) => { + res.send("Auth"); + }); + router.GET("/:id", (req, res) => { + res.send({ id: req.params.id }); + }); +}; diff --git a/test/benchmark/hello-world/express.js b/test/benchmark/hello-world/express.js new file mode 100644 index 0000000..afc1730 --- /dev/null +++ b/test/benchmark/hello-world/express.js @@ -0,0 +1,9 @@ +const express = require("express"); + +const app = express(); + +app.get("/", (req, res) => { + res.send("Hello world"); +}); + +app.listen(3000); diff --git a/test/benchmark/hello-world/fastify.js b/test/benchmark/hello-world/fastify.js new file mode 100644 index 0000000..cd22929 --- /dev/null +++ b/test/benchmark/hello-world/fastify.js @@ -0,0 +1,9 @@ +const fastify = require("fastify"); + +const app = fastify(); + +app.get("/", (req, res) => { + res.send("Hello world"); +}); + +app.listen(3000); diff --git a/test/benchmark/hello-world/koa.js b/test/benchmark/hello-world/koa.js new file mode 100644 index 0000000..6d41251 --- /dev/null +++ b/test/benchmark/hello-world/koa.js @@ -0,0 +1,8 @@ +const koa = require("koa"); +const app = new koa(); + +app.use(async (ctx) => { + ctx.body = "Hello World"; +}); + +app.listen(3000); diff --git a/test/benchmark/hello-world/unnamed.js b/test/benchmark/hello-world/unnamed.js new file mode 100644 index 0000000..eeaf948 --- /dev/null +++ b/test/benchmark/hello-world/unnamed.js @@ -0,0 +1,9 @@ +const unnamed = require("unnamed-js"); + +const server = unnamed({ port: 3000 }); + +const { GET, POST, PUT, PATCH, DELETE } = server; + +GET("/", (req, res) => { + res.send("Hello world"); +}); diff --git a/test/benchmark/index.js b/test/benchmark/index.js new file mode 100644 index 0000000..de7ae97 --- /dev/null +++ b/test/benchmark/index.js @@ -0,0 +1,24 @@ +var apiBenchmark = require("api-benchmark"); + +var service = { + server1: "http://localhost:3000/user", +}; + +var routes = { + route1: "route1", + route2: "route2", + route3: { + method: "post", + route: "/user", + data: { + test: true, + moreData: "aString", + }, + }, +}; + +apiBenchmark.measure(service, routes, function (err, results) { + console.log({ stats: results.server1.route1 }); + console.log({ stats: results.server1.route2 }); + console.log({ stats: results.server1.route3 }); +}); diff --git a/test/benchmark/load.js b/test/benchmark/load.js new file mode 100644 index 0000000..ee35906 --- /dev/null +++ b/test/benchmark/load.js @@ -0,0 +1,24 @@ +"use strict"; + +const autocannon = require("autocannon"); + +autocannon( + { + url: "http://localhost:3000", + connections: 10, //default + pipelining: 1, // default + duration: 10, // default + }, + console.log +); + +// async/await +async function foo() { + const result = await autocannon({ + url: "http://localhost:3000", + connections: 10, //default + pipelining: 1, // default + duration: 10, // default + }); + console.log(result); +} diff --git a/test/ddos-stress/index.js b/test/ddos-stress/index.js new file mode 100644 index 0000000..bb2aa49 --- /dev/null +++ b/test/ddos-stress/index.js @@ -0,0 +1,7 @@ +var Stress = require("ddos-stress"); + +// Create new instance of DDoS Stress +var stress = new Stress(); + +// Run stress on server +// Stress.run("http://localhost:3000", 10); diff --git a/test/demo/app.js b/test/demo/app.js new file mode 100644 index 0000000..89d3b38 --- /dev/null +++ b/test/demo/app.js @@ -0,0 +1,11 @@ +const unnamed = require("unnamed-js"); + +const PORT = process.env.PORT || 8080; +const server = unnamed({ port: PORT }); +const { GET } = server; + +server.router(require("./routers")); + +GET("/", (request, response) => { + response.send("Hello world"); +}); diff --git a/demoV2/package.json b/test/demo/package.json similarity index 57% rename from demoV2/package.json rename to test/demo/package.json index 7f71714..255cb60 100644 --- a/demoV2/package.json +++ b/test/demo/package.json @@ -1,17 +1,16 @@ { - "name": "demoV2", + "name": "demo", "version": "1.0.0", "description": "", "main": "app.js", "scripts": { - "dev": "nodemon app.js" + "start": "node", + "dev": "nodemon" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { - "cors": "^2.8.5", - "dotenv": "^16.0.0", - "mongoose": "^6.2.1" + "unnamed-js": "^2.0.13" } } diff --git a/test/demo/routers/index.js b/test/demo/routers/index.js new file mode 100644 index 0000000..eafada2 --- /dev/null +++ b/test/demo/routers/index.js @@ -0,0 +1,8 @@ +const routes = [ + { + prefix:'user', + router: require('./user.route') + } +] + +module.exports = routes \ No newline at end of file diff --git a/test/demo/routers/user.route.js b/test/demo/routers/user.route.js new file mode 100644 index 0000000..aee870b --- /dev/null +++ b/test/demo/routers/user.route.js @@ -0,0 +1,6 @@ +const router = ({ GET, POST, PUT, PATCH, DELETE }) => { + GET("/", (request, response) => { + response.send("User route"); + }); +}; +module.exports = router; diff --git a/test/index.js b/test/index.js new file mode 100644 index 0000000..5910fbb --- /dev/null +++ b/test/index.js @@ -0,0 +1,39 @@ +const unnamed = require("unnamed-js"); +const morgan = require("morgan"); + +const server = unnamed( + { + port: 3000, + }, + { log: false } +); + +const { GET, POST, PUT, PATCH, DELETE } = server; + +server.middleware(morgan("tiny")); + +server.registerRouter({ + prefix: "auth", + router: require("./auth.route"), +}); +GET("/", (req, res) => { + res.goto("/user"); +}); +GET("/user", (req, res) => { + res.send("Hello" + req.user); +}); +POST("/user", (req, res) => { + res.send("POST" + req.user); +}); +PUT("/user", (req, res) => { + res.send("PUT" + req.user); +}); +PATCH("/user", (req, res) => { + res.send("PATCH" + req.user); +}); +DELETE("/user", (req, res) => { + res.send("DELETE" + req.user); +}); +GET("/user/:id", (req, res) => { + res.send({ userId: req.params.id }); +}); diff --git a/test/package.json b/test/package.json new file mode 100644 index 0000000..0301def --- /dev/null +++ b/test/package.json @@ -0,0 +1,21 @@ +{ + "name": "test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "dev": "nodemon index.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "api-benchmark": "^1.0.1", + "ddos-stress": "^0.1.0", + "express": "^4.17.3", + "fastify": "^3.27.4", + "koa": "^2.13.4", + "morgan": "^1.10.0", + "unnamed-js": "^1.1.2" + } +}