-
Notifications
You must be signed in to change notification settings - Fork 17
/
helpers.js
120 lines (109 loc) · 4.28 KB
/
helpers.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
* @fileOverview A collection of helper functions that makes
* working with Stick middleware easier.
*/
const objects = require("ringo/utils/objects");
const {urlEncode} = require("ringo/utils/http");
/**
* Resolve a module name or module object to a JSGI application.
*/
const resolveApp = exports.resolveApp = function(app) {
let resolved = typeof app === "string" ? require(app) : app;
if (typeof resolved !== "function") {
if (resolved && typeof resolved.app === "function") {
resolved = resolved.app;
} else {
throw new Error("Could not resolve app: " + app);
}
}
return resolved;
};
// declared after resolveApp to solve cyclic dependency
const mount = require("./middleware/mount");
/**
* Return a link to an action configured using the `route` middleware.
*
* The link's URL is generated from the bindings argument as described for
* the [urlFor helper](#urlFor).
*
* @param {object|string} app the application to link to
* @param {object} bindings an object containing the bindings for the target URL.
* @param {string} text the link text.
*/
exports.linkTo = function(app, bindings, text) {
const href = urlFor(app, bindings);
text = text || href;
return '<a href="' + href + '">' + text + '</a>';
};
/**
* Return a URL for an action configured using the `mount` and `route` middlewares.
*
* The `app` argument specifies the Stick application to link to, either as reference
* to the app itself or as module id of a module exporting the app as `app`.
* The `bindings` argument contains information needed to determine the target
* action within that application. Properties in the bindings argument are interpreted
* as follows:
*
* * The `action` property, if present, identifies the name of the action to link to.
* Action names are determined from the path arguments provided to the `route`
* middleware by removing all placeholders and the leading slash. For example,
* the name for an action routed with `/edit/:id` is "edit".
*
* * Properties in the bindings object that have a placeholder with the same name in
* the target route are used to provide the value for this placeholder.
* For example, to URI path to an action in application `app` routed with "/edit/:id" with
* id `5` can be generated as follows:
*
* urlFor(app, {action: "edit", id: 5})
*
* * All other properties in the bindings object are set as query parameters in the
* generated URL. For example, if "index" is a route with no placeholders then calling
* `urlFor("index", {do: "search"})` will generate the URL "/?do=search".
*
* Note that the values for the current request are used as default values for `action`
* and route placehoders, so if you want to use to a different action or placeholder value
* you need to make that explicit.
*
* @param {object|string} app the application to link to
* @param {object} bindings an object containing the bindings for the target URL.
*/
const urlFor = exports.urlFor = function(app, bindings) {
bindings = bindings ? objects.clone(bindings) : {};
if (!app) {
throw new Error("app binding is missing");
}
app = resolveApp(app);
let baseUri = app.base || mount.lookup(app) || "";
if (app.route) {
baseUri += app.route.reverse(bindings);
}
// add any bindings left over by route.reverse() to the query string
let unbound = Object.keys(bindings);
if (unbound.length) {
baseUri += "?" + urlEncode(bindings);
}
return baseUri;
};
/**
* Create a response that redirects the client to a different URL.
* @param {string|object} app either the URL as string or an app
* to be passed to `urlFor`
* @param {bindings} bindings to pass to `urlFor` if first argument is an app.
* @returns {object} a JSGI response that will redirect the client to the
* specified target
*/
exports.redirectTo = function(app, bindings) {
let target;
if (typeof app === "function") {
target = urlFor(app, bindings);
} else if (typeof app === "string") {
target = app;
} else {
throw new Error("redirectTo requires an argument of type string or object");
}
return {
status: 303,
headers: { "location": target },
body: ["See other: " + target]
};
};