@tryghost/url-utils 2.0.8 → 3.0.1

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 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
- * @param {Object} options.apiVersions configuration object which has defined `all` property which is an array of keys for other available properties
22
- * @param {('v2' | 'v3' | 'v4' | 'canary')} [options.defaultApiVersion='v4'] default API version which is one of the values from options.apiVersions
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
- var subDir = this.getSubdir();
44
+ let subDir = this.getSubdir();
80
45
 
81
46
  if (!_.isEmpty(subDir)) {
82
47
  return this._config.slugs.concat([subDir.split('/').pop()]);
@@ -143,18 +108,18 @@ module.exports = class UrlUtils {
143
108
  // This is probably not the right place for this, but it's the best place for now
144
109
  // @TODO: rewrite, very hard to read, create private functions!
145
110
  urlFor(context, data, absolute) {
146
- var urlPath = '/',
147
- secure,
148
- imagePathRe,
149
- knownObjects = ['image', 'nav'],
150
- baseUrl,
151
- hostname,
152
-
153
- // this will become really big
154
- knownPaths = {
155
- home: '/',
156
- sitemap_xsl: '/sitemap.xsl'
157
- };
111
+ let urlPath = '/';
112
+ let secure;
113
+ let imagePathRe;
114
+ let knownObjects = ['image', 'nav'];
115
+ let baseUrl;
116
+ let hostname;
117
+
118
+ // this will become really big
119
+ let knownPaths = {
120
+ home: '/',
121
+ sitemap_xsl: '/sitemap.xsl'
122
+ };
158
123
 
159
124
  // Make data properly optional
160
125
  if (_.isBoolean(data)) {
@@ -208,32 +173,29 @@ module.exports = class UrlUtils {
208
173
  urlPath = urlPath.replace(/\/$/, '');
209
174
  }
210
175
  } else if (context === 'admin') {
211
- urlPath = this.getAdminUrl() || this.getSiteUrl();
176
+ let adminUrl = this.getAdminUrl() || this.getSiteUrl();
177
+ let adminPath = '/ghost/';
212
178
 
213
179
  if (absolute) {
214
- urlPath += 'ghost/';
180
+ urlPath = this.urlJoin(adminUrl, adminPath);
215
181
  } else {
216
- urlPath = '/ghost/';
182
+ urlPath = adminPath;
217
183
  }
218
184
  } else if (context === 'api') {
219
- urlPath = this.getAdminUrl() || this.getSiteUrl();
220
- let apiPath = this.getApiPath();
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
- }
185
+ let adminUrl = this.getAdminUrl() || this.getSiteUrl();
186
+ let apiPath = this._config.baseApiPath + '/';
230
187
 
231
- if (data && data.version) {
232
- apiPath = this.getApiPath({version: data.version, type: data.versionType});
188
+ if (data.type && ['admin', 'content'].includes(data.type)) {
189
+ apiPath += data.type;
190
+ } else {
191
+ apiPath += this._config.defaultApiType;
233
192
  }
234
193
 
194
+ // Ensure we end with a trailing slash
195
+ apiPath += '/';
196
+
235
197
  if (absolute) {
236
- urlPath = urlPath.replace(/\/$/, '') + apiPath;
198
+ urlPath = this.urlJoin(adminUrl, apiPath);
237
199
  } else {
238
200
  urlPath = apiPath;
239
201
  }
@@ -257,7 +219,7 @@ module.exports = class UrlUtils {
257
219
  }
258
220
 
259
221
  redirectToAdmin(status, res, adminPath) {
260
- var redirectUrl = this.urlJoin(this.urlFor('admin', true), adminPath, '/');
222
+ let redirectUrl = this.urlJoin(this.urlFor('admin', true), adminPath, '/');
261
223
 
262
224
  if (status === 301) {
263
225
  return this.redirect301(res, redirectUrl);
@@ -8,6 +8,18 @@ function extractSrcsetUrls(srcset = '') {
8
8
  });
9
9
  }
10
10
 
11
+ function extractStyleUrls(style = '') {
12
+ const urls = [];
13
+ const regex = /url\(['|"]([^)]+)['|"]\)/g;
14
+ let match;
15
+
16
+ while ((match = regex.exec(style)) !== null) {
17
+ urls.push(match[1]);
18
+ }
19
+
20
+ return urls;
21
+ }
22
+
11
23
  function htmlTransform(html = '', siteUrl, transformFunction, itemPath, _options) {
12
24
  const defaultOptions = {assetsOnly: false, secure: false};
13
25
  const options = Object.assign({}, defaultOptions, _options || {});
@@ -42,7 +54,7 @@ function htmlTransform(html = '', siteUrl, transformFunction, itemPath, _options
42
54
  }
43
55
 
44
56
  // find all of the relative url attributes that we care about
45
- ['href', 'src', 'srcset'].forEach((attributeName) => {
57
+ ['href', 'src', 'srcset', 'style'].forEach((attributeName) => {
46
58
  htmlContent('[' + attributeName + ']').each((ix, el) => {
47
59
  // ignore <stream> elems and html inside of <code> elements
48
60
  if (el.name === 'stream' || htmlContent(el).closest('code').length) {
@@ -57,8 +69,14 @@ function htmlTransform(html = '', siteUrl, transformFunction, itemPath, _options
57
69
  el = htmlContent(el);
58
70
  const originalValue = el.attr(attributeName);
59
71
 
60
- if (attributeName === 'srcset') {
61
- const urls = extractSrcsetUrls(originalValue);
72
+ if (attributeName === 'srcset' || attributeName === 'style') {
73
+ let urls;
74
+
75
+ if (attributeName === 'srcset') {
76
+ urls = extractSrcsetUrls(originalValue);
77
+ } else {
78
+ urls = extractStyleUrls(originalValue);
79
+ }
62
80
  const absoluteUrls = urls.map(url => transformFunction(url, siteUrl, itemPath, options));
63
81
  let transformedValue = originalValue;
64
82
 
@@ -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": "2.0.8",
3
+ "version": "3.0.1",
4
4
  "repository": "https://github.com/TryGhost/SDK/tree/master/packages/url-utils",
5
5
  "author": "Ghost Foundation",
6
6
  "license": "MIT",
7
- "main": "lib/index.js",
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.1.5",
22
- "c8": "7.11.0",
23
- "mocha": "7.2.0",
24
- "rewire": "5.0.0",
22
+ "@tryghost/config-url-helpers": "0.1.8",
23
+ "c8": "7.11.2",
24
+ "mocha": "10.0.0",
25
+ "rewire": "6.0.0",
25
26
  "should": "13.2.3",
26
- "sinon": "9.2.4"
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": "36ffe70168eb2ad3eaefa0dc63a35697b284c9e7"
37
+ "gitHead": "2f7fb1fef3f2464f000974c8e0e13e25eabd6f6d"
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;