UNPKG

4.84 kBJavaScriptView Raw
1/*
2 * Copyright 2015 the original author or authors
3 * @license MIT, see LICENSE.txt for details
4 *
5 * @author Scott Andrews
6 */
7
8(function (define) {
9 'use strict';
10
11 var undef;
12
13 define(function (require) {
14
15 var uriEncoder, operations, prefixRE;
16
17 uriEncoder = require('./uriEncoder');
18
19 prefixRE = /^([^:]*):([0-9]+)$/;
20 operations = {
21 '': { first: '', separator: ',', named: false, empty: '', encoder: uriEncoder.encode },
22 '+': { first: '', separator: ',', named: false, empty: '', encoder: uriEncoder.encodeURL },
23 '#': { first: '#', separator: ',', named: false, empty: '', encoder: uriEncoder.encodeURL },
24 '.': { first: '.', separator: '.', named: false, empty: '', encoder: uriEncoder.encode },
25 '/': { first: '/', separator: '/', named: false, empty: '', encoder: uriEncoder.encode },
26 ';': { first: ';', separator: ';', named: true, empty: '', encoder: uriEncoder.encode },
27 '?': { first: '?', separator: '&', named: true, empty: '=', encoder: uriEncoder.encode },
28 '&': { first: '&', separator: '&', named: true, empty: '=', encoder: uriEncoder.encode },
29 '=': { reserved: true },
30 ',': { reserved: true },
31 '!': { reserved: true },
32 '@': { reserved: true },
33 '|': { reserved: true }
34 };
35
36 function apply(operation, expression, params) {
37 /*jshint maxcomplexity:11 */
38 return expression.split(',').reduce(function (result, variable) {
39 var opts, value;
40
41 opts = {};
42 if (variable.slice(-1) === '*') {
43 variable = variable.slice(0, -1);
44 opts.explode = true;
45 }
46 if (prefixRE.test(variable)) {
47 var prefix = prefixRE.exec(variable);
48 variable = prefix[1];
49 opts.maxLength = parseInt(prefix[2]);
50 }
51
52 variable = uriEncoder.decode(variable);
53 value = params[variable];
54
55 if (value === undef || value === null) {
56 return result;
57 }
58 if (Array.isArray(value)) {
59 result += value.reduce(function (result, value) {
60 if (result.length) {
61 result += opts.explode ? operation.separator : ',';
62 if (operation.named && opts.explode) {
63 result += operation.encoder(variable);
64 result += value.length ? '=' : operation.empty;
65 }
66 }
67 else {
68 result += operation.first;
69 if (operation.named) {
70 result += operation.encoder(variable);
71 result += value.length ? '=' : operation.empty;
72 }
73 }
74 result += operation.encoder(value);
75 return result;
76 }, '');
77 }
78 else if (typeof value === 'object') {
79 result += Object.keys(value).reduce(function (result, name) {
80 if (result.length) {
81 result += opts.explode ? operation.separator : ',';
82 }
83 else {
84 result += operation.first;
85 if (operation.named && !opts.explode) {
86 result += operation.encoder(variable);
87 result += value[name].length ? '=' : operation.empty;
88 }
89 }
90 result += operation.encoder(name);
91 result += opts.explode ? '=' : ',';
92 result += operation.encoder(value[name]);
93 return result;
94 }, '');
95 }
96 else {
97 value = String(value);
98 if (opts.maxLength) {
99 value = value.slice(0, opts.maxLength);
100 }
101 result += result.length ? operation.separator : operation.first;
102 if (operation.named) {
103 result += operation.encoder(variable);
104 result += value.length ? '=' : operation.empty;
105 }
106 result += operation.encoder(value);
107 }
108
109 return result;
110 }, '');
111 }
112
113 function expandExpression(expression, params) {
114 var operation;
115
116 operation = operations[expression.slice(0,1)];
117 if (operation) {
118 expression = expression.slice(1);
119 }
120 else {
121 operation = operations[''];
122 }
123
124 if (operation.reserved) {
125 throw new Error('Reserved expression operations are not supported');
126 }
127
128 return apply(operation, expression, params);
129 }
130
131 function expandTemplate(template, params) {
132 var start, end, uri;
133
134 uri = '';
135 end = 0;
136 while (true) {
137 start = template.indexOf('{', end);
138 if (start === -1) {
139 // no more expressions
140 uri += template.slice(end);
141 break;
142 }
143 uri += template.slice(end, start);
144 end = template.indexOf('}', start) + 1;
145 uri += expandExpression(template.slice(start + 1, end - 1), params);
146 }
147
148 return uri;
149 }
150
151 return {
152
153 /**
154 * Expand a URI Template with parameters to form a URI.
155 *
156 * Full implementation (level 4) of rfc6570.
157 * @see https://tools.ietf.org/html/rfc6570
158 *
159 * @param {string} template URI template
160 * @param {Object} [params] params to apply to the template durring expantion
161 * @returns {string} expanded URI
162 */
163 expand: expandTemplate
164
165 };
166
167 });
168
169}(
170 typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }
171 // Boilerplate for AMD and Node
172));