Skip to content
29 changes: 20 additions & 9 deletions packages/url-utils/src/utils/absolute-to-relative.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
// @ts-nocheck
// require the whatwg compatible URL library (same behaviour in node and browser)
const {URL} = require('url');
const stripSubdirectoryFromPath = require('./strip-subdirectory-from-path').default;
import {URL} from 'url';
import stripSubdirectoryFromPath from './strip-subdirectory-from-path';

export interface AbsoluteToRelativeOptions {
ignoreProtocol: boolean;
withoutSubdirectory: boolean;
assetsOnly: boolean;
staticImageUrlPrefix: string;
}

export type AbsoluteToRelativeOptionsInput = Partial<AbsoluteToRelativeOptions>;

/**
* Convert an absolute URL to a root-relative path if it matches the supplied root domain.
Expand All @@ -13,8 +20,8 @@ const stripSubdirectoryFromPath = require('./strip-subdirectory-from-path').defa
* @param {boolean} [options.withoutSubdirectory=false] Strip the root subdirectory from the returned path
* @returns {string} The passed-in url or a relative path
*/
const absoluteToRelative = function absoluteToRelative(url, rootUrl, _options = {}) {
const defaultOptions = {
const absoluteToRelative = function absoluteToRelative(url: string, rootUrl?: string, _options: AbsoluteToRelativeOptionsInput = {}): string {
const defaultOptions: AbsoluteToRelativeOptions = {
ignoreProtocol: true,
withoutSubdirectory: false,
assetsOnly: false,
Expand All @@ -29,8 +36,8 @@ const absoluteToRelative = function absoluteToRelative(url, rootUrl, _options =
}
}

let parsedUrl;
let parsedRoot;
let parsedUrl: URL;
let parsedRoot: URL | undefined;

try {
parsedUrl = new URL(url, 'http://relative');
Expand All @@ -44,6 +51,10 @@ const absoluteToRelative = function absoluteToRelative(url, rootUrl, _options =
return url;
}

if (!parsedRoot) {
return url;
}

const matchesHost = parsedUrl.host === parsedRoot.host;
const matchesProtocol = parsedUrl.protocol === parsedRoot.protocol;
const matchesPath = parsedUrl.pathname.indexOf(parsedRoot.pathname) === 0;
Expand All @@ -61,4 +72,4 @@ const absoluteToRelative = function absoluteToRelative(url, rootUrl, _options =
return url;
};

module.exports = absoluteToRelative;
export default absoluteToRelative;
46 changes: 33 additions & 13 deletions packages/url-utils/src/utils/absolute-to-transform-ready.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
// @ts-nocheck
const {URL} = require('url');
const absoluteToRelative = require('./absolute-to-relative');
import type {TransformReadyReplacementOptions} from './types';
import absoluteToRelative, {type AbsoluteToRelativeOptionsInput} from './absolute-to-relative';
import {URL} from 'url';

function isRelative(url) {
let parsedInput;
export interface AbsoluteToTransformReadyOptions extends TransformReadyReplacementOptions {
withoutSubdirectory: boolean;
ignoreProtocol: boolean;
assetsOnly: boolean;
staticImageUrlPrefix: string;
staticFilesUrlPrefix?: string;
staticMediaUrlPrefix?: string;
imageBaseUrl?: string | null;
filesBaseUrl?: string | null;
mediaBaseUrl?: string | null;
}

export type AbsoluteToTransformReadyOptionsInput = Partial<AbsoluteToTransformReadyOptions>;

function isRelative(url: string): boolean {
let parsedInput: URL;
try {
parsedInput = new URL(url, 'http://relative');
} catch (e) {
Expand All @@ -14,16 +28,22 @@ function isRelative(url) {
return parsedInput.origin === 'http://relative';
}

const absoluteToTransformReady = function (url, root, _options = {}) {
const defaultOptions = {
const absoluteToTransformReady = function (
url: string,
root: string,
_options: AbsoluteToTransformReadyOptionsInput = {}
): string {
const defaultOptions: AbsoluteToTransformReadyOptions = {
replacementStr: '__GHOST_URL__',
withoutSubdirectory: true,
staticImageUrlPrefix: 'content/images',
staticFilesUrlPrefix: 'content/files',
staticMediaUrlPrefix: 'content/media',
imageBaseUrl: null,
filesBaseUrl: null,
mediaBaseUrl: null
mediaBaseUrl: null,
ignoreProtocol: true,
assetsOnly: false
};
const options = Object.assign({}, defaultOptions, _options);

Expand All @@ -33,30 +53,30 @@ const absoluteToTransformReady = function (url, root, _options = {}) {

// convert to relative with stripped subdir
// always returns root-relative starting with forward slash
const rootRelativeUrl = absoluteToRelative(url, root, options);
const rootRelativeUrl = absoluteToRelative(url, root, options as AbsoluteToRelativeOptionsInput);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to type cast here? Can we instead make sure that options is of type AbsoluteToTransformReadyOptions and then it overlaps?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I've updated AbsoluteToTransformReadyOptions to extend AbsoluteToRelativeOptions, which makes the types properly overlap. Removed type casts.


if (isRelative(rootRelativeUrl)) {
return `${options.replacementStr}${rootRelativeUrl}`;
}

if (options.mediaBaseUrl) {
const mediaRelativeUrl = absoluteToRelative(url, options.mediaBaseUrl, options);
const mediaRelativeUrl = absoluteToRelative(url, options.mediaBaseUrl, options as AbsoluteToRelativeOptionsInput);

if (isRelative(mediaRelativeUrl)) {
return `${options.replacementStr}${mediaRelativeUrl}`;
}
}

if (options.filesBaseUrl) {
const filesRelativeUrl = absoluteToRelative(url, options.filesBaseUrl, options);
const filesRelativeUrl = absoluteToRelative(url, options.filesBaseUrl, options as AbsoluteToRelativeOptionsInput);

if (isRelative(filesRelativeUrl)) {
return `${options.replacementStr}${filesRelativeUrl}`;
}
}

if (options.imageBaseUrl) {
const imageRelativeUrl = absoluteToRelative(url, options.imageBaseUrl, options);
const imageRelativeUrl = absoluteToRelative(url, options.imageBaseUrl, options as AbsoluteToRelativeOptionsInput);

if (isRelative(imageRelativeUrl)) {
return `${options.replacementStr}${imageRelativeUrl}`;
Expand All @@ -66,4 +86,4 @@ const absoluteToTransformReady = function (url, root, _options = {}) {
return url;
};

module.exports = absoluteToTransformReady;
export default absoluteToTransformReady;
19 changes: 12 additions & 7 deletions packages/url-utils/src/utils/build-early-exit-match.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
// @ts-nocheck
function escapeRegExp(string) {
import type {BaseUrlOptionsInput} from './types';

function escapeRegExp(string: string): string {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

type BuildEarlyExitMatchOptions = BaseUrlOptionsInput & {
ignoreProtocol?: boolean;
};

/**
* Build a regex pattern that matches any of the configured base URLs (site URL + CDN URLs).
* This is used for early exit optimizations - if content doesn't contain any of these URLs,
Expand All @@ -16,14 +21,14 @@ function escapeRegExp(string) {
* @param {boolean} [options.ignoreProtocol=true] - Whether to strip protocol from URLs
* @returns {string|null} Regex pattern matching any configured base URL, or null if none configured
*/
function buildEarlyExitMatch(siteUrl, options = {}) {
function buildEarlyExitMatch(siteUrl: string, options: BuildEarlyExitMatchOptions = {}): string | null {
const candidates = [siteUrl, options.imageBaseUrl, options.filesBaseUrl, options.mediaBaseUrl]
.filter(Boolean)
.map((value) => {
.filter((value): value is string => Boolean(value))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value is string doesn't match the actual implementation 🤔

The Boolean(value) check is making sure it's a non empty string - I think we should change this line to the following which is slightly more correct and at least enforces the string type

.filter((value: string | null): value is string => typeof value === 'string' && value.length > 0)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

.map((value: string) => {
let normalized = options.ignoreProtocol ? value.replace(/http:|https:/, '') : value;
return normalized.replace(/\/$/, '');
})
.filter(Boolean)
.filter((value): value is string => Boolean(value))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in this case we can just do (value: string): boolean => Boolean(value)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

.map(escapeRegExp);

if (!candidates.length) {
Expand All @@ -37,7 +42,7 @@ function buildEarlyExitMatch(siteUrl, options = {}) {
return `(?:${candidates.join('|')})`;
}

module.exports = {
export default {
buildEarlyExitMatch,
escapeRegExp
};
2 changes: 1 addition & 1 deletion packages/url-utils/src/utils/html-absolute-to-relative.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-nocheck
const htmlTransform = require('./html-transform');
const absoluteToRelative = require('./absolute-to-relative');
const absoluteToRelative = require('./absolute-to-relative').default;

function htmlAbsoluteToRelative(html = '', siteUrl, _options) {
const defaultOptions = {assetsOnly: false, ignoreProtocol: true};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-nocheck
const htmlTransform = require('./html-transform');
const absoluteToTransformReady = require('./absolute-to-transform-ready');
const {buildEarlyExitMatch} = require('./build-early-exit-match');
const absoluteToTransformReady = require('./absolute-to-transform-ready').default;
const {buildEarlyExitMatch} = require('./build-early-exit-match').default;

const htmlAbsoluteToTransformReady = function (html = '', siteUrl, _options) {
const defaultOptions = {assetsOnly: false, ignoreProtocol: true};
Expand Down
2 changes: 1 addition & 1 deletion packages/url-utils/src/utils/html-relative-to-absolute.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-nocheck
const htmlTransform = require('./html-transform');
const relativeToAbsolute = require('./relative-to-absolute');
const relativeToAbsolute = require('./relative-to-absolute').default;

function htmlRelativeToAbsolute(html = '', siteUrl, itemPath, _options) {
const defaultOptions = {assetsOnly: false, secure: false};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-nocheck
const htmlTransform = require('./html-transform');
const relativeToTransformReady = require('./relative-to-transform-ready');
const relativeToTransformReady = require('./relative-to-transform-ready').default;

const htmlRelativeToTransformReady = function (html = '', root, itemPath, _options) {
// itemPath is optional, if it's an object may be the options param instead
Expand Down
21 changes: 14 additions & 7 deletions packages/url-utils/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
// @ts-nocheck
import absoluteToRelative from './absolute-to-relative';
import absoluteToTransformReady from './absolute-to-transform-ready';
import deduplicateDoubleSlashes from './deduplicate-double-slashes';
import deduplicateSubdirectory from './deduplicate-subdirectory';
import isSSL from './is-ssl';
import relativeToAbsolute from './relative-to-absolute';
import relativeToTransformReady from './relative-to-transform-ready';
import replacePermalink from './replace-permalink';
import stripSubdirectoryFromPath from './strip-subdirectory-from-path';
import toTransformReady from './to-transform-ready';
import transformReadyToAbsolute from './transform-ready-to-absolute';
import transformReadyToRelative from './transform-ready-to-relative';
import urlJoin from './url-join';

module.exports = {
absoluteToRelative: require('./absolute-to-relative'),
absoluteToTransformReady: require('./absolute-to-transform-ready'),
absoluteToRelative,
absoluteToTransformReady,
deduplicateDoubleSlashes,
deduplicateSubdirectory,
htmlAbsoluteToRelative: require('./html-absolute-to-relative'),
Expand All @@ -35,12 +42,12 @@ module.exports = {
plaintextAbsoluteToTransformReady: require('./plaintext-absolute-to-transform-ready'),
plaintextRelativeToTransformReady: require('./plaintext-relative-to-transform-ready'),
plaintextToTransformReady: require('./plaintext-to-transform-ready'),
relativeToAbsolute: require('./relative-to-absolute'),
relativeToTransformReady: require('./relative-to-transform-ready'),
relativeToAbsolute,
relativeToTransformReady,
replacePermalink,
stripSubdirectoryFromPath,
toTransformReady: require('./to-transform-ready'),
transformReadyToAbsolute: require('./transform-ready-to-absolute'),
transformReadyToRelative: require('./transform-ready-to-relative'),
toTransformReady,
transformReadyToAbsolute,
transformReadyToRelative,
urlJoin
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-nocheck
const absoluteToRelative = require('./absolute-to-relative');
const absoluteToRelative = require('./absolute-to-relative').default;
const lexicalTransform = require('./lexical-transform');

function lexicalAbsoluteToRelative(serializedLexical, siteUrl, _options = {}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-nocheck
const absoluteToTransformReady = require('./absolute-to-transform-ready');
const absoluteToTransformReady = require('./absolute-to-transform-ready').default;
const lexicalTransform = require('./lexical-transform');

function lexicalAbsoluteToRelative(serializedLexical, siteUrl, _options = {}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-nocheck
const relativeToAbsolute = require('./relative-to-absolute');
const relativeToAbsolute = require('./relative-to-absolute').default;
const lexicalTransform = require('./lexical-transform');

function lexicalRelativeToAbsolute(serializedLexical, siteUrl, itemPath, _options = {}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-nocheck
const relativeToTransformReady = require('./relative-to-transform-ready');
const relativeToTransformReady = require('./relative-to-transform-ready').default;
const lexicalTransform = require('./lexical-transform');

function lexicalRelativeToTransformReady(serializedLexical, siteUrl, itemPath, _options = {}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-nocheck
const markdownTransform = require('./markdown-transform');
const absoluteToRelative = require('./absolute-to-relative');
const absoluteToRelative = require('./absolute-to-relative').default;
const htmlAbsoluteToRelative = require('./html-absolute-to-relative');

function markdownAbsoluteToRelative(markdown = '', siteUrl, _options = {}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// @ts-nocheck
const markdownTransform = require('./markdown-transform');
const absoluteToTransformReady = require('./absolute-to-transform-ready');
const absoluteToTransformReady = require('./absolute-to-transform-ready').default;
const htmlAbsoluteToTransformReady = require('./html-absolute-to-transform-ready');
const {buildEarlyExitMatch} = require('./build-early-exit-match');
const {buildEarlyExitMatch} = require('./build-early-exit-match').default;

function markdownAbsoluteToTransformReady(markdown = '', siteUrl, _options = {}) {
const defaultOptions = {assetsOnly: false, ignoreProtocol: true};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-nocheck
const markdownTransform = require('./markdown-transform');
const htmlRelativeToAbsolute = require('./html-relative-to-absolute');
const relativeToAbsolute = require('./relative-to-absolute');
const relativeToAbsolute = require('./relative-to-absolute').default;

function markdownRelativeToAbsolute(markdown = '', siteUrl, itemPath, _options = {}) {
const defaultOptions = {assetsOnly: false};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-nocheck
const markdownTransform = require('./markdown-transform');
const htmlRelativeToTransformReady = require('./html-relative-to-transform-ready');
const relativeToTransformReady = require('./relative-to-transform-ready');
const relativeToTransformReady = require('./relative-to-transform-ready').default;

function markdownRelativeToTransformReady(markdown = '', siteUrl, itemPath, _options = {}) {
const defaultOptions = {assetsOnly: false};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-nocheck
const absoluteToRelative = require('./absolute-to-relative');
const absoluteToRelative = require('./absolute-to-relative').default;
const mobiledocTransform = require('./mobiledoc-transform');

function mobiledocAbsoluteToRelative(serializedMobiledoc, siteUrl, _options = {}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-nocheck
const absoluteToTransformReady = require('./absolute-to-transform-ready');
const absoluteToTransformReady = require('./absolute-to-transform-ready').default;
const mobiledocTransform = require('./mobiledoc-transform');

function mobiledocAbsoluteToRelative(serializedMobiledoc, siteUrl, _options = {}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-nocheck
const relativeToAbsolute = require('./relative-to-absolute');
const relativeToAbsolute = require('./relative-to-absolute').default;
const mobiledocTransform = require('./mobiledoc-transform');

function mobiledocRelativeToAbsolute(serializedMobiledoc, siteUrl, itemPath, _options = {}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-nocheck
const relativeToTransformReady = require('./relative-to-transform-ready');
const relativeToTransformReady = require('./relative-to-transform-ready').default;
const mobiledocTransform = require('./mobiledoc-transform');

function mobiledocRelativeToTransformReady(serializedMobiledoc, siteUrl, itemPath, _options = {}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-nocheck
const absoluteToTransformReady = require('./absolute-to-transform-ready');
const {escapeRegExp} = require('./build-early-exit-match');
const absoluteToTransformReady = require('./absolute-to-transform-ready').default;
const {escapeRegExp} = require('./build-early-exit-match').default;

function buildLinkRegex(rootUrl, options = {}) {
// Build a regex that matches links from ANY configured base URL (site + CDNs)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-nocheck
const relativeToTransformReady = require('./relative-to-transform-ready');
const relativeToTransformReady = require('./relative-to-transform-ready').default;

const plaintextRelativeToTransformReady = function plaintextRelativeToTransformReady(plaintext, rootUrl, itemPath, options) {
// itemPath is optional, if it's an object may be the options param instead
Expand Down
Loading