@tryghost/url-utils 2.1.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +1 -0
- package/lib/{index.js → url-utils.js} +35 -79
- package/lib/utils/index.js +0 -2
- package/package.json +11 -10
- package/lib/utils/get-api-path.js +0 -18
- package/lib/utils/get-version-path.js +0 -20
package/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./lib/url-utils');
|
|
@@ -18,65 +18,30 @@ module.exports = class UrlUtils {
|
|
|
18
18
|
* @param {Function} options.getSubdir
|
|
19
19
|
* @param {Function} options.getSiteUrl
|
|
20
20
|
* @param {Function} options.getAdminUrl Ghost instance admin URL
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
* @param {('content' | 'admin')} [options.defaultApiType='content'] default API type to be used and is one of the values from options.apiVersions
|
|
21
|
+
* @param {String} [options.baseApiPath='/ghost/api'] static prefix for serving API. Should not te passed in, unless the API is being run under custom URL
|
|
22
|
+
* @param {('content' | 'admin')} [options.defaultApiType='content'] default API type to be used
|
|
24
23
|
* @param {Object} [options.slugs] object with 2 properties reserved and protected containing arrays of special case slugs
|
|
25
24
|
* @param {Number} [options.redirectCacheMaxAge]
|
|
26
|
-
* @param {String} [options.baseApiPath='/ghost/api'] static prefix for serving API. Should not te passed in, unless the API is being run under custom URL
|
|
27
25
|
* @param {String} [options.staticImageUrlPrefix='content/images'] static prefix for serving images. Should not be passed in, unless customizing ghost instance image storage
|
|
28
26
|
*/
|
|
29
27
|
constructor(options = {}) {
|
|
30
28
|
const defaultOptions = {
|
|
31
|
-
apiVersions: null,
|
|
32
29
|
slugs: null,
|
|
33
30
|
redirectCacheMaxAge: null,
|
|
34
31
|
baseApiPath: '/ghost/api',
|
|
35
|
-
defaultApiVersion: 'v4',
|
|
36
32
|
defaultApiType: 'content',
|
|
37
33
|
staticImageUrlPrefix: 'content/images'
|
|
38
34
|
};
|
|
39
35
|
|
|
40
36
|
this._config = assignOptions({}, defaultOptions, options);
|
|
41
37
|
|
|
42
|
-
this._defaultApiPathOptions = {
|
|
43
|
-
baseApiPath: this._config.baseApiPath,
|
|
44
|
-
version: this._config.defaultApiVersion,
|
|
45
|
-
type: this._config.defaultApiType,
|
|
46
|
-
apiVersions: this._config.apiVersions
|
|
47
|
-
};
|
|
48
|
-
|
|
49
38
|
this.getSubdir = options.getSubdir;
|
|
50
39
|
this.getSiteUrl = options.getSiteUrl;
|
|
51
40
|
this.getAdminUrl = options.getAdminUrl;
|
|
52
41
|
}
|
|
53
42
|
|
|
54
|
-
/**
|
|
55
|
-
* Returns API path combining base path and path for specific version asked or deprecated by default
|
|
56
|
-
* @param {Object} options
|
|
57
|
-
* @param {string} [options.version="v4"] for which to get the path (v2, v3, canary, etc)
|
|
58
|
-
* @param {string} [options.type="content"] (admin, content, members)
|
|
59
|
-
* @return {string} API Path for version
|
|
60
|
-
*/
|
|
61
|
-
getApiPath(options = {}) {
|
|
62
|
-
const _options = assignOptions({}, this._defaultApiPathOptions, options);
|
|
63
|
-
return utils.getApiPath(_options);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Returns path containing only the path for the specific version asked or deprecated by default
|
|
68
|
-
* @param {Object} options
|
|
69
|
-
* @param {string} [options.version="v4"] for which to get the path (v2, v3, canary, etc)
|
|
70
|
-
* @param {string} [options.type="content"] (admin, content)
|
|
71
|
-
* @return {string} API version path
|
|
72
|
-
*/
|
|
73
|
-
getVersionPath(options = {}) {
|
|
74
|
-
const _options = assignOptions({}, this._defaultApiPathOptions, options);
|
|
75
|
-
return utils.getVersionPath(_options);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
43
|
getProtectedSlugs() {
|
|
79
|
-
|
|
44
|
+
let subDir = this.getSubdir();
|
|
80
45
|
|
|
81
46
|
if (!_.isEmpty(subDir)) {
|
|
82
47
|
return this._config.slugs.concat([subDir.split('/').pop()]);
|
|
@@ -105,15 +70,14 @@ module.exports = class UrlUtils {
|
|
|
105
70
|
// Parameters:
|
|
106
71
|
// - urlPath - string which must start and end with a slash
|
|
107
72
|
// - absolute (optional, default:false) - boolean whether or not the url should be absolute
|
|
108
|
-
// - secure (optional, default:false) - boolean whether or not to force SSL
|
|
109
73
|
// Returns:
|
|
110
74
|
// - a URL which always ends with a slash
|
|
111
|
-
createUrl(urlPath = '/', absolute = false,
|
|
75
|
+
createUrl(urlPath = '/', absolute = false, trailingSlash) {
|
|
112
76
|
let base;
|
|
113
77
|
|
|
114
78
|
// create base of url, always ends without a slash
|
|
115
79
|
if (absolute) {
|
|
116
|
-
base = this.getSiteUrl(
|
|
80
|
+
base = this.getSiteUrl();
|
|
117
81
|
} else {
|
|
118
82
|
base = this.getSubdir();
|
|
119
83
|
}
|
|
@@ -143,18 +107,17 @@ module.exports = class UrlUtils {
|
|
|
143
107
|
// This is probably not the right place for this, but it's the best place for now
|
|
144
108
|
// @TODO: rewrite, very hard to read, create private functions!
|
|
145
109
|
urlFor(context, data, absolute) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
};
|
|
110
|
+
let urlPath = '/';
|
|
111
|
+
let imagePathRe;
|
|
112
|
+
let knownObjects = ['image', 'nav'];
|
|
113
|
+
let baseUrl;
|
|
114
|
+
let hostname;
|
|
115
|
+
|
|
116
|
+
// this will become really big
|
|
117
|
+
let knownPaths = {
|
|
118
|
+
home: '/',
|
|
119
|
+
sitemap_xsl: '/sitemap.xsl'
|
|
120
|
+
};
|
|
158
121
|
|
|
159
122
|
// Make data properly optional
|
|
160
123
|
if (_.isBoolean(data)) {
|
|
@@ -162,9 +125,6 @@ module.exports = class UrlUtils {
|
|
|
162
125
|
data = null;
|
|
163
126
|
}
|
|
164
127
|
|
|
165
|
-
// Can pass 'secure' flag in either context or data arg
|
|
166
|
-
secure = (context && context.secure) || (data && data.secure);
|
|
167
|
-
|
|
168
128
|
if (_.isObject(context) && context.relativeUrl) {
|
|
169
129
|
urlPath = context.relativeUrl;
|
|
170
130
|
} else if (_.isString(context) && _.indexOf(knownObjects, context) !== -1) {
|
|
@@ -176,15 +136,14 @@ module.exports = class UrlUtils {
|
|
|
176
136
|
if (absolute) {
|
|
177
137
|
// Remove the sub-directory from the URL because ghostConfig will add it back.
|
|
178
138
|
urlPath = urlPath.replace(new RegExp('^' + this.getSubdir()), '');
|
|
179
|
-
baseUrl = this.getSiteUrl(
|
|
139
|
+
baseUrl = this.getSiteUrl().replace(/\/$/, '');
|
|
180
140
|
urlPath = baseUrl + urlPath;
|
|
181
141
|
}
|
|
182
142
|
|
|
183
143
|
return urlPath;
|
|
184
144
|
} else if (context === 'nav' && data.nav) {
|
|
185
145
|
urlPath = data.nav.url;
|
|
186
|
-
|
|
187
|
-
baseUrl = this.getSiteUrl(secure);
|
|
146
|
+
baseUrl = this.getSiteUrl();
|
|
188
147
|
hostname = baseUrl.split('//')[1];
|
|
189
148
|
|
|
190
149
|
// If the hostname is present in the url
|
|
@@ -200,7 +159,7 @@ module.exports = class UrlUtils {
|
|
|
200
159
|
}
|
|
201
160
|
}
|
|
202
161
|
} else if (context === 'home' && absolute) {
|
|
203
|
-
urlPath = this.getSiteUrl(
|
|
162
|
+
urlPath = this.getSiteUrl();
|
|
204
163
|
|
|
205
164
|
// CASE: there are cases where urlFor('home') needs to be returned without trailing
|
|
206
165
|
// slash e. g. the `{{@site.url}}` helper. See https://github.com/TryGhost/Ghost/issues/8569
|
|
@@ -208,32 +167,29 @@ module.exports = class UrlUtils {
|
|
|
208
167
|
urlPath = urlPath.replace(/\/$/, '');
|
|
209
168
|
}
|
|
210
169
|
} else if (context === 'admin') {
|
|
211
|
-
|
|
170
|
+
let adminUrl = this.getAdminUrl() || this.getSiteUrl();
|
|
171
|
+
let adminPath = '/ghost/';
|
|
212
172
|
|
|
213
173
|
if (absolute) {
|
|
214
|
-
urlPath
|
|
174
|
+
urlPath = this.urlJoin(adminUrl, adminPath);
|
|
215
175
|
} else {
|
|
216
|
-
urlPath =
|
|
176
|
+
urlPath = adminPath;
|
|
217
177
|
}
|
|
218
178
|
} else if (context === 'api') {
|
|
219
|
-
|
|
220
|
-
let apiPath = this.
|
|
221
|
-
|
|
222
|
-
// CASE: with or without protocol? If your blog url (or admin url) is configured to http, it's still possible that e.g. nginx allows both https+http.
|
|
223
|
-
// So it depends how you serve your blog. The main focus here is to avoid cors problems.
|
|
224
|
-
// @TODO: rename cors
|
|
225
|
-
if (data && data.cors) {
|
|
226
|
-
if (!urlPath.match(/^https:/)) {
|
|
227
|
-
urlPath = urlPath.replace(/^.*?:\/\//g, '//');
|
|
228
|
-
}
|
|
229
|
-
}
|
|
179
|
+
let adminUrl = this.getAdminUrl() || this.getSiteUrl();
|
|
180
|
+
let apiPath = this._config.baseApiPath + '/';
|
|
230
181
|
|
|
231
|
-
if (data && data.
|
|
232
|
-
apiPath
|
|
182
|
+
if (data.type && ['admin', 'content'].includes(data.type)) {
|
|
183
|
+
apiPath += data.type;
|
|
184
|
+
} else {
|
|
185
|
+
apiPath += this._config.defaultApiType;
|
|
233
186
|
}
|
|
234
187
|
|
|
188
|
+
// Ensure we end with a trailing slash
|
|
189
|
+
apiPath += '/';
|
|
190
|
+
|
|
235
191
|
if (absolute) {
|
|
236
|
-
urlPath =
|
|
192
|
+
urlPath = this.urlJoin(adminUrl, apiPath);
|
|
237
193
|
} else {
|
|
238
194
|
urlPath = apiPath;
|
|
239
195
|
}
|
|
@@ -248,7 +204,7 @@ module.exports = class UrlUtils {
|
|
|
248
204
|
return urlPath;
|
|
249
205
|
}
|
|
250
206
|
|
|
251
|
-
return this.createUrl(urlPath, absolute
|
|
207
|
+
return this.createUrl(urlPath, absolute);
|
|
252
208
|
}
|
|
253
209
|
|
|
254
210
|
redirect301(res, redirectUrl) {
|
|
@@ -257,7 +213,7 @@ module.exports = class UrlUtils {
|
|
|
257
213
|
}
|
|
258
214
|
|
|
259
215
|
redirectToAdmin(status, res, adminPath) {
|
|
260
|
-
|
|
216
|
+
let redirectUrl = this.urlJoin(this.urlFor('admin', true), adminPath, '/');
|
|
261
217
|
|
|
262
218
|
if (status === 301) {
|
|
263
219
|
return this.redirect301(res, redirectUrl);
|
package/lib/utils/index.js
CHANGED
|
@@ -3,8 +3,6 @@ module.exports = {
|
|
|
3
3
|
absoluteToTransformReady: require('./absolute-to-transform-ready'),
|
|
4
4
|
deduplicateDoubleSlashes: require('./deduplicate-double-slashes'),
|
|
5
5
|
deduplicateSubdirectory: require('./deduplicate-subdirectory'),
|
|
6
|
-
getApiPath: require('./get-api-path'),
|
|
7
|
-
getVersionPath: require('./get-version-path'),
|
|
8
6
|
htmlAbsoluteToRelative: require('./html-absolute-to-relative'),
|
|
9
7
|
htmlRelativeToAbsolute: require('./html-relative-to-absolute'),
|
|
10
8
|
htmlAbsoluteToTransformReady: require('./html-absolute-to-transform-ready'),
|
package/package.json
CHANGED
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tryghost/url-utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"repository": "https://github.com/TryGhost/SDK/tree/master/packages/url-utils",
|
|
5
5
|
"author": "Ghost Foundation",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"main": "
|
|
7
|
+
"main": "index.js",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"dev": "echo \"Implement me!\"",
|
|
10
|
-
"test": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura mocha './test/**/*.test.js'",
|
|
10
|
+
"test": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --reporter html mocha './test/**/*.test.js'",
|
|
11
11
|
"lint": "eslint . --ext .js --cache",
|
|
12
12
|
"posttest": "yarn lint"
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
|
-
"lib/"
|
|
15
|
+
"lib/",
|
|
16
|
+
"index.js"
|
|
16
17
|
],
|
|
17
18
|
"publishConfig": {
|
|
18
19
|
"access": "public"
|
|
19
20
|
},
|
|
20
21
|
"devDependencies": {
|
|
21
|
-
"@tryghost/config-url-helpers": "0.
|
|
22
|
-
"c8": "7.11.
|
|
23
|
-
"mocha": "
|
|
24
|
-
"rewire": "
|
|
22
|
+
"@tryghost/config-url-helpers": "1.0.0",
|
|
23
|
+
"c8": "7.11.2",
|
|
24
|
+
"mocha": "10.0.0",
|
|
25
|
+
"rewire": "6.0.0",
|
|
25
26
|
"should": "13.2.3",
|
|
26
|
-
"sinon": "
|
|
27
|
+
"sinon": "14.0.0"
|
|
27
28
|
},
|
|
28
29
|
"dependencies": {
|
|
29
30
|
"cheerio": "^0.22.0",
|
|
@@ -33,5 +34,5 @@
|
|
|
33
34
|
"remark-footnotes": "^1.0.0",
|
|
34
35
|
"unist-util-visit": "^2.0.0"
|
|
35
36
|
},
|
|
36
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "76ea47794eb7eb1e2b6e9d5b68d52653efc5b85a"
|
|
37
38
|
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
const getVersionPath = require('./get-version-path');
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Returns API path combining base path and path for specific version/type
|
|
5
|
-
* @param {Object} options
|
|
6
|
-
* @param {string} options.version (v2, v3, v4, canary, etc)
|
|
7
|
-
* @param {string} options.type (admin, content, members)
|
|
8
|
-
* @param {string} options.baseApiPath
|
|
9
|
-
* @param {Object} options.apiVersions
|
|
10
|
-
* @return {string} API Path for version
|
|
11
|
-
*/
|
|
12
|
-
function getApiPath(options) {
|
|
13
|
-
const versionPath = getVersionPath(options);
|
|
14
|
-
|
|
15
|
-
return `${options.baseApiPath}${versionPath}`;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
module.exports = getApiPath;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Returns API path combining base path and path for specific version/type
|
|
3
|
-
* @param {Object} options
|
|
4
|
-
* @param {string} options.version (v2, v3, canary, etc)
|
|
5
|
-
* @param {string} options.type (admin, content, members)
|
|
6
|
-
* @param {Object} options.apiVersions
|
|
7
|
-
* @return {string} API Path for version
|
|
8
|
-
*/
|
|
9
|
-
function getVersionPath(options) {
|
|
10
|
-
let {version, type} = options;
|
|
11
|
-
let versionData = options.apiVersions[version];
|
|
12
|
-
|
|
13
|
-
if (typeof versionData === 'string') {
|
|
14
|
-
versionData = options.apiVersions[versionData];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return `/${versionData[type]}/`;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
module.exports = getVersionPath;
|