diff --git a/packages/url-utils/index.js b/packages/url-utils/index.js deleted file mode 100644 index ae745e82f..000000000 --- a/packages/url-utils/index.js +++ /dev/null @@ -1,2 +0,0 @@ -module.exports = require('./lib/UrlUtils'); - diff --git a/packages/url-utils/package.json b/packages/url-utils/package.json index 9f13dc676..6e83dbe11 100644 --- a/packages/url-utils/package.json +++ b/packages/url-utils/package.json @@ -8,20 +8,19 @@ }, "author": "Ghost Foundation", "license": "MIT", - "main": "index.js", - "types": "lib/UrlUtils.d.ts", + "main": "lib/index.js", + "types": "lib/index.d.ts", "scripts": { "dev": "echo \"Implement me!\"", "pretest": "yarn build", "test": "NODE_ENV=testing c8 --src lib --all --reporter text --reporter cobertura --reporter html mocha './test/**/*.test.js'", "build": "tsc -p tsconfig.json", - "lint": "eslint src test index.js --ext .js,.ts --cache", + "lint": "eslint src test --ext .js,.ts --cache", "prepare": "NODE_ENV=production yarn build", "posttest": "yarn lint" }, "files": [ - "lib/", - "index.js" + "lib/" ], "publishConfig": { "access": "public" diff --git a/packages/url-utils/src/UrlUtils.ts b/packages/url-utils/src/UrlUtils.ts index a57104761..d607fabc3 100644 --- a/packages/url-utils/src/UrlUtils.ts +++ b/packages/url-utils/src/UrlUtils.ts @@ -1,18 +1,84 @@ -// @ts-nocheck // Contains all path information to be used throughout the codebase. -const _ = require('lodash'); -const utils = require('./utils'); +import * as _ from 'lodash'; +import utils from './utils'; +import type { + HtmlTransformOptionsInput, + MarkdownTransformOptionsInput, + MobiledocTransformOptionsInput, + LexicalTransformOptionsInput, + MobiledocCardTransformer, + BaseUrlOptionsInput +} from './utils/types'; +import type {AbsoluteToRelativeOptionsInput} from './utils/absolute-to-relative'; +import type {RelativeToAbsoluteOptionsInput} from './utils/relative-to-absolute'; +import type {AbsoluteToTransformReadyOptionsInput as AbsoluteToTransformReadyOptionsInputType} from './utils/absolute-to-transform-ready'; +import type {RelativeToTransformReadyOptionsInput as RelativeToTransformReadyOptionsInputType} from './utils/relative-to-transform-ready'; +import type {ToTransformReadyOptions} from './utils/to-transform-ready'; +import type {TransformReadyToAbsoluteOptionsInput} from './utils/transform-ready-to-absolute'; +import type {TransformReadyReplacementOptionsInput as TransformReadyToRelativeOptionsInput} from './utils/types'; + +interface ExpressResponse { + set(headers: Record): void; + redirect(status: number, url: string): void; + redirect(url: string): void; +} + +interface AssetBaseUrls { + image: string | null; + files: string | null; + media: string | null; +} + +interface UrlUtilsConfig { + slugs: string[] | null; + redirectCacheMaxAge: number | null; + baseApiPath: string; + defaultApiType: 'content' | 'admin'; + staticImageUrlPrefix: string; + staticFilesUrlPrefix: string; + staticMediaUrlPrefix: string; + cardTransformers?: MobiledocCardTransformer[]; +} + +interface UrlUtilsOptions { + getSubdir?: () => string; + getSiteUrl?: () => string; + getAdminUrl?: () => string; + baseApiPath?: string; + defaultApiType?: 'content' | 'admin'; + slugs?: { + reserved?: string[]; + protected?: string[]; + } | null; + redirectCacheMaxAge?: number | null; + staticImageUrlPrefix?: string; + staticFilesUrlPrefix?: string; + staticMediaUrlPrefix?: string; + assetBaseUrls?: { + image?: string | null; + files?: string | null; + media?: string | null; + }; + cardTransformers?: MobiledocCardTransformer[]; +} // similar to Object.assign but will not override defaults if a source value is undefined -function assignOptions(target, ...sources) { +function assignOptions>(target: T, ...sources: Array>): T { const options = sources.map((x) => { return Object.entries(x) .filter(([, value]) => value !== undefined) - .reduce((obj, [key, value]) => (obj[key] = value, obj), {}); + .reduce((obj, [key, value]) => (obj[key] = value, obj), {} as Record); }); - return Object.assign(target, ...options); + return Object.assign(target, ...options) as T; } -module.exports = class UrlUtils { + +export default class UrlUtils { + private _config: UrlUtilsConfig; + private _assetBaseUrls: AssetBaseUrls; + public getSubdir: () => string; + public getSiteUrl: () => string; + public getAdminUrl: () => string; + /** * Initialization method to pass in URL configurations * @param {Object} options @@ -31,8 +97,8 @@ module.exports = class UrlUtils { * @param {string} [options.assetBaseUrls.files] files asset CDN base URL * @param {string} [options.assetBaseUrls.media] media asset CDN base URL */ - constructor(options = {}) { - const defaultOptions = { + constructor(options: UrlUtilsOptions = {}) { + const defaultOptions: UrlUtilsConfig = { slugs: null, redirectCacheMaxAge: null, baseApiPath: '/ghost/api', @@ -42,7 +108,7 @@ module.exports = class UrlUtils { staticMediaUrlPrefix: 'content/media' }; - this._config = assignOptions({}, defaultOptions, options); + this._config = assignOptions({}, defaultOptions as unknown as Record, options as unknown as Record) as UrlUtilsConfig; const assetBaseUrls = options.assetBaseUrls || {}; this._assetBaseUrls = { @@ -51,12 +117,16 @@ module.exports = class UrlUtils { media: assetBaseUrls.media || null }; - this.getSubdir = options.getSubdir; - this.getSiteUrl = options.getSiteUrl; - this.getAdminUrl = options.getAdminUrl; + this.getSubdir = options.getSubdir || (() => ''); + this.getSiteUrl = options.getSiteUrl || (() => ''); + this.getAdminUrl = options.getAdminUrl || (() => ''); } - _assetOptionDefaults() { + private _assetOptionDefaults(): BaseUrlOptionsInput & { + staticImageUrlPrefix: string; + staticFilesUrlPrefix: string; + staticMediaUrlPrefix: string; + } { return { staticImageUrlPrefix: this._config.staticImageUrlPrefix, staticFilesUrlPrefix: this._config.staticFilesUrlPrefix, @@ -67,17 +137,21 @@ module.exports = class UrlUtils { }; } - _buildAssetOptions(additionalDefaults = {}, options) { + private _buildAssetOptions(additionalDefaults: Record = {}, options?: Record): Record { return assignOptions({}, this._assetOptionDefaults(), additionalDefaults, options || {}); } - getProtectedSlugs() { - let subDir = this.getSubdir(); + getProtectedSlugs(): string[] { + const subDir = this.getSubdir(); if (!_.isEmpty(subDir)) { - return this._config.slugs.concat([subDir.split('/').pop()]); + const lastSegment = subDir.split('/').pop(); + if (this._config.slugs && lastSegment) { + return this._config.slugs.concat([lastSegment]); + } + return lastSegment ? [lastSegment] : []; } else { - return this._config.slugs; + return this._config.slugs || []; } } @@ -86,7 +160,7 @@ module.exports = class UrlUtils { * @param {string} arguments takes arguments and concats those to a valid path/URL. * @return {string} URL concatinated URL/path of arguments. */ - urlJoin(...parts) { + urlJoin(...parts: string[]): string { return utils.urlJoin(parts, {rootUrl: this.getSiteUrl()}); } @@ -103,8 +177,8 @@ module.exports = class UrlUtils { // - absolute (optional, default:false) - boolean whether or not the url should be absolute // Returns: // - a URL which always ends with a slash - createUrl(urlPath = '/', absolute = false, trailingSlash) { - let base; + createUrl(urlPath: string = '/', absolute: boolean = false, trailingSlash?: boolean): string { + let base: string; // create base of url, always ends without a slash if (absolute) { @@ -137,15 +211,15 @@ module.exports = class UrlUtils { // - absolute (optional, default:false) - boolean whether or not the url should be absolute // This is probably not the right place for this, but it's the best place for now // @TODO: rewrite, very hard to read, create private functions! - urlFor(context, data, absolute) { - let urlPath = '/'; - let imagePathRe; - let knownObjects = ['image', 'nav']; - let baseUrl; - let hostname; + urlFor(context: string | {relativeUrl: string} | {image?: string} | {nav?: {url: string}}, data?: Record | boolean | {trailingSlash?: boolean; type?: 'admin' | 'content'} | null, absolute?: boolean): string { + let urlPath: string = '/'; + let imagePathRe: RegExp | undefined; + const knownObjects: string[] = ['image', 'nav']; + let baseUrl: string | undefined; + let hostname: string | undefined; // this will become really big - let knownPaths = { + const knownPaths: Record = { home: '/', sitemap_xsl: '/sitemap.xsl' }; @@ -156,13 +230,14 @@ module.exports = class UrlUtils { data = null; } - if (_.isObject(context) && context.relativeUrl) { - urlPath = context.relativeUrl; + if (_.isObject(context) && !_.isArray(context) && 'relativeUrl' in context && typeof (context as {relativeUrl: string}).relativeUrl === 'string') { + const relativeUrl = (context as {relativeUrl: string}).relativeUrl; + urlPath = relativeUrl || '/'; } else if (_.isString(context) && _.indexOf(knownObjects, context) !== -1) { - if (context === 'image' && data.image) { - urlPath = data.image; + if (context === 'image' && data && typeof data === 'object' && !_.isArray(data) && 'image' in data && typeof data.image === 'string') { + urlPath = data.image as string; imagePathRe = new RegExp('^' + this.getSubdir() + '/' + this._config.staticImageUrlPrefix); - absolute = imagePathRe.test(data.image) ? absolute : false; + absolute = imagePathRe.test(urlPath) ? (absolute || false) : false; if (absolute) { // Remove the sub-directory from the URL because ghostConfig will add it back. @@ -172,8 +247,8 @@ module.exports = class UrlUtils { } return urlPath; - } else if (context === 'nav' && data.nav) { - urlPath = data.nav.url; + } else if (context === 'nav' && data && typeof data === 'object' && !_.isArray(data) && 'nav' in data && data.nav && typeof data.nav === 'object' && !_.isArray(data.nav) && 'url' in data.nav && typeof data.nav.url === 'string') { + urlPath = (data.nav as {url: string}).url; baseUrl = this.getSiteUrl(); hostname = baseUrl.split('//')[1]; @@ -194,11 +269,11 @@ module.exports = class UrlUtils { // CASE: there are cases where urlFor('home') needs to be returned without trailing // slash e. g. the `{{@site.url}}` helper. See https://github.com/TryGhost/Ghost/issues/8569 - if (data && data.trailingSlash === false) { + if (data && typeof data === 'object' && !_.isArray(data) && 'trailingSlash' in data && data.trailingSlash === false) { urlPath = urlPath.replace(/\/$/, ''); } } else if (context === 'admin') { - let adminUrl = this.getAdminUrl() || this.getSiteUrl(); + const adminUrl = this.getAdminUrl() || this.getSiteUrl(); let adminPath = '/ghost/'; if (absolute) { @@ -207,10 +282,10 @@ module.exports = class UrlUtils { urlPath = adminPath; } } else if (context === 'api') { - let adminUrl = this.getAdminUrl() || this.getSiteUrl(); + const adminUrl = this.getAdminUrl() || this.getSiteUrl(); let apiPath = this._config.baseApiPath + '/'; - if (data.type && ['admin', 'content'].includes(data.type)) { + if (data && typeof data === 'object' && !_.isArray(data) && 'type' in data && typeof data.type === 'string' && ['admin', 'content'].includes(data.type)) { apiPath += data.type; } else { apiPath += this._config.defaultApiType; @@ -238,64 +313,76 @@ module.exports = class UrlUtils { return this.createUrl(urlPath, absolute); } - redirect301(res, redirectUrl) { + redirect301(res: ExpressResponse, redirectUrl: string): void { res.set({'Cache-Control': 'public, max-age=' + this._config.redirectCacheMaxAge}); - return res.redirect(301, redirectUrl); + res.redirect(301, redirectUrl); } - redirectToAdmin(status, res, adminPath) { - let redirectUrl = this.urlJoin(this.urlFor('admin', true), adminPath, '/'); + redirectToAdmin(status: number, res: ExpressResponse, adminPath: string): void { + const redirectUrl = this.urlJoin(this.urlFor('admin', true), adminPath, '/'); if (status === 301) { - return this.redirect301(res, redirectUrl); + this.redirect301(res, redirectUrl); + } else { + res.redirect(redirectUrl); } - return res.redirect(redirectUrl); } - absoluteToRelative(url, options) { + absoluteToRelative(url: string, options?: AbsoluteToRelativeOptionsInput): string { return utils.absoluteToRelative(url, this.getSiteUrl(), options); } - relativeToAbsolute(url, options) { - return utils.relativeToAbsolute(url, this.getSiteUrl(), options); + relativeToAbsolute(url: string, options?: RelativeToAbsoluteOptionsInput): string { + // Original code passes options as third parameter (itemPath), preserving that behavior + return utils.relativeToAbsolute(url, this.getSiteUrl(), options || null, undefined); } - toTransformReady(url, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + toTransformReady(url: string, itemPath: string | null | ToTransformReadyOptions, options?: ToTransformReadyOptions): string { + let finalItemPath: string | null = null; + let finalOptions: ToTransformReadyOptions | undefined = options; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath as ToTransformReadyOptions; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } - const _options = this._buildAssetOptions({}, options); - return utils.toTransformReady(url, this.getSiteUrl(), itemPath, _options); + const _options = this._buildAssetOptions({}, finalOptions) as ToTransformReadyOptions; + return utils.toTransformReady(url, this.getSiteUrl(), finalItemPath, _options); } - absoluteToTransformReady(url, options) { - const _options = this._buildAssetOptions({}, options); + absoluteToTransformReady(url: string, options?: AbsoluteToTransformReadyOptionsInputType): string { + const _options = this._buildAssetOptions({}, options) as AbsoluteToTransformReadyOptionsInputType; return utils.absoluteToTransformReady(url, this.getSiteUrl(), _options); } - relativeToTransformReady(url, options) { - const _options = this._buildAssetOptions({}, options); + relativeToTransformReady(url: string, options?: RelativeToTransformReadyOptionsInputType): string { + const _options = this._buildAssetOptions({}, options) as RelativeToTransformReadyOptionsInputType; return utils.relativeToTransformReady(url, this.getSiteUrl(), _options); } - transformReadyToAbsolute(url, options) { - const _options = this._buildAssetOptions({}, options); + transformReadyToAbsolute(url: string, options?: TransformReadyToAbsoluteOptionsInput): string { + const _options = this._buildAssetOptions({}, options) as TransformReadyToAbsoluteOptionsInput; return utils.transformReadyToAbsolute(url, this.getSiteUrl(), _options); } - transformReadyToRelative(url, options) { - const _options = this._buildAssetOptions({}, options); + transformReadyToRelative(url: string, options?: TransformReadyToRelativeOptionsInput): string { + const _options = this._buildAssetOptions({}, options) as TransformReadyToRelativeOptionsInput; return utils.transformReadyToRelative(url, this.getSiteUrl(), _options); } - htmlToTransformReady(html, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + htmlToTransformReady(html: string, itemPath: string | null | HtmlTransformOptionsInput, options?: HtmlTransformOptionsInput): string { + let finalItemPath: string | null = null; + let finalOptions: HtmlTransformOptionsInput | undefined = options; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } - const _options = this._buildAssetOptions({}, options); - return utils.htmlToTransformReady(html, this.getSiteUrl(), itemPath, _options); + const _options = this._buildAssetOptions({}, finalOptions) as HtmlTransformOptionsInput; + return utils.htmlToTransformReady(html, this.getSiteUrl(), finalItemPath, _options); } /** @@ -308,192 +395,247 @@ module.exports = class UrlUtils { * absolute urls. Returns an object. The html string can be accessed by calling `html()` on * the variable that takes the result of this function */ - htmlRelativeToAbsolute(html, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + htmlRelativeToAbsolute(html: string, itemPath: string | null | HtmlTransformOptionsInput, options?: HtmlTransformOptionsInput): string { + let finalItemPath: string | null = null; + let finalOptions: HtmlTransformOptionsInput | undefined = options; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } const _options = this._buildAssetOptions({ assetsOnly: false - }, options); - return utils.htmlRelativeToAbsolute(html, this.getSiteUrl(), itemPath, _options); + }, finalOptions) as HtmlTransformOptionsInput; + return utils.htmlRelativeToAbsolute(html, this.getSiteUrl(), finalItemPath, _options); } - htmlRelativeToTransformReady(html, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + htmlRelativeToTransformReady(html: string, itemPath: string | null | RelativeToTransformReadyOptionsInputType, options?: RelativeToTransformReadyOptionsInputType): string { + let finalItemPath: string | null = null; + let finalOptions: RelativeToTransformReadyOptionsInputType | undefined = options; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } const _options = this._buildAssetOptions({ assetsOnly: false - }, options); - return utils.htmlRelativeToTransformReady(html, this.getSiteUrl(), itemPath, _options); + }, finalOptions) as RelativeToTransformReadyOptionsInputType; + return utils.htmlRelativeToTransformReady(html, this.getSiteUrl(), finalItemPath, _options); } - htmlAbsoluteToRelative(html, options = {}) { + htmlAbsoluteToRelative(html: string, options: HtmlTransformOptionsInput = {}): string { const _options = this._buildAssetOptions({ assetsOnly: false - }, options); + }, options) as HtmlTransformOptionsInput; return utils.htmlAbsoluteToRelative(html, this.getSiteUrl(), _options); } - htmlAbsoluteToTransformReady(html, options = {}) { + htmlAbsoluteToTransformReady(html: string, options: AbsoluteToTransformReadyOptionsInputType = {}): string { const _options = this._buildAssetOptions({ assetsOnly: false - }, options); + }, options) as AbsoluteToTransformReadyOptionsInputType; return utils.htmlAbsoluteToTransformReady(html, this.getSiteUrl(), _options); } - markdownToTransformReady(markdown, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + markdownToTransformReady(markdown: string, itemPath: string | null | MarkdownTransformOptionsInput, options?: MarkdownTransformOptionsInput): string { + let finalItemPath: string | null = null; + let finalOptions: MarkdownTransformOptionsInput | undefined = options; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } - const _options = this._buildAssetOptions({}, options); - return utils.markdownToTransformReady(markdown, this.getSiteUrl(), itemPath, _options); + const _options = this._buildAssetOptions({}, finalOptions) as MarkdownTransformOptionsInput; + return utils.markdownToTransformReady(markdown, this.getSiteUrl(), finalItemPath, _options); } - markdownRelativeToAbsolute(markdown, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + markdownRelativeToAbsolute(markdown: string, itemPath: string | null | MarkdownTransformOptionsInput, options?: MarkdownTransformOptionsInput): string { + let finalItemPath: string | null = null; + let finalOptions: MarkdownTransformOptionsInput | undefined = options; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } const _options = this._buildAssetOptions({ assetsOnly: false - }, options); - return utils.markdownRelativeToAbsolute(markdown, this.getSiteUrl(), itemPath, _options); + }, finalOptions) as MarkdownTransformOptionsInput; + return utils.markdownRelativeToAbsolute(markdown, this.getSiteUrl(), finalItemPath, _options); } - markdownRelativeToTransformReady(markdown, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + markdownRelativeToTransformReady(markdown: string, itemPath: string | null | MarkdownTransformOptionsInput, options?: MarkdownTransformOptionsInput): string { + let finalItemPath: string | null = null; + let finalOptions: MarkdownTransformOptionsInput | undefined = options; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } const _options = this._buildAssetOptions({ assetsOnly: false - }, options); - return utils.markdownRelativeToTransformReady(markdown, this.getSiteUrl(), itemPath, _options); + }, finalOptions) as MarkdownTransformOptionsInput; + return utils.markdownRelativeToTransformReady(markdown, this.getSiteUrl(), finalItemPath, _options); } - markdownAbsoluteToRelative(markdown, options = {}) { + markdownAbsoluteToRelative(markdown: string, options: MarkdownTransformOptionsInput = {}): string { const _options = this._buildAssetOptions({ assetsOnly: false - }, options); + }, options) as MarkdownTransformOptionsInput; return utils.markdownAbsoluteToRelative(markdown, this.getSiteUrl(), _options); } - markdownAbsoluteToTransformReady(markdown, options) { + markdownAbsoluteToTransformReady(markdown: string, options: AbsoluteToTransformReadyOptionsInputType = {}): string { const _options = this._buildAssetOptions({ assetsOnly: false - }, options); + }, options) as AbsoluteToTransformReadyOptionsInputType; return utils.markdownAbsoluteToTransformReady(markdown, this.getSiteUrl(), _options); } - mobiledocToTransformReady(serializedMobiledoc, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + mobiledocToTransformReady(serializedMobiledoc: string, itemPath: string | null | MobiledocTransformOptionsInput, options?: MobiledocTransformOptionsInput): string { + let finalItemPath: string | null = null; + let finalOptions: MobiledocTransformOptionsInput | undefined = options; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } const _options = this._buildAssetOptions({ cardTransformers: this._config.cardTransformers - }, options); - return utils.mobiledocToTransformReady(serializedMobiledoc, this.getSiteUrl(), itemPath, _options); + }, finalOptions) as MobiledocTransformOptionsInput; + return utils.mobiledocToTransformReady(serializedMobiledoc, this.getSiteUrl(), finalItemPath, _options); } - mobiledocRelativeToAbsolute(serializedMobiledoc, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + mobiledocRelativeToAbsolute(serializedMobiledoc: string, itemPath: string | null | MobiledocTransformOptionsInput, options?: MobiledocTransformOptionsInput): string { + let finalItemPath: string | null = null; + let finalOptions: MobiledocTransformOptionsInput | undefined = options; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } const _options = this._buildAssetOptions({ assetsOnly: false, cardTransformers: this._config.cardTransformers - }, options); - return utils.mobiledocRelativeToAbsolute(serializedMobiledoc, this.getSiteUrl(), itemPath, _options); + }, finalOptions) as MobiledocTransformOptionsInput; + return utils.mobiledocRelativeToAbsolute(serializedMobiledoc, this.getSiteUrl(), finalItemPath, _options); } - mobiledocRelativeToTransformReady(serializedMobiledoc, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + mobiledocRelativeToTransformReady(serializedMobiledoc: string, itemPath: string | null | MobiledocTransformOptionsInput, options?: MobiledocTransformOptionsInput): string { + let finalItemPath: string | null = null; + let finalOptions: MobiledocTransformOptionsInput | undefined = options; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } const _options = this._buildAssetOptions({ assetsOnly: false, cardTransformers: this._config.cardTransformers - }, options); - return utils.mobiledocRelativeToTransformReady(serializedMobiledoc, this.getSiteUrl(), itemPath, _options); + }, finalOptions) as MobiledocTransformOptionsInput; + return utils.mobiledocRelativeToTransformReady(serializedMobiledoc, this.getSiteUrl(), finalItemPath, _options); } - mobiledocAbsoluteToRelative(serializedMobiledoc, options = {}) { + mobiledocAbsoluteToRelative(serializedMobiledoc: string, options: MobiledocTransformOptionsInput = {}): string { const _options = this._buildAssetOptions({ assetsOnly: false, cardTransformers: this._config.cardTransformers - }, options); + }, options) as MobiledocTransformOptionsInput; return utils.mobiledocAbsoluteToRelative(serializedMobiledoc, this.getSiteUrl(), _options); } - mobiledocAbsoluteToTransformReady(serializedMobiledoc, options = {}) { + mobiledocAbsoluteToTransformReady(serializedMobiledoc: string, options: MobiledocTransformOptionsInput = {}): string { const _options = this._buildAssetOptions({ assetsOnly: false, cardTransformers: this._config.cardTransformers - }, options); + }, options) as MobiledocTransformOptionsInput; return utils.mobiledocAbsoluteToTransformReady(serializedMobiledoc, this.getSiteUrl(), _options); } - lexicalToTransformReady(serializedLexical, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + lexicalToTransformReady(serializedLexical: string, itemPath: string | null | LexicalTransformOptionsInput, options?: LexicalTransformOptionsInput): string { + let finalItemPath: string | null = null; + let finalOptions: LexicalTransformOptionsInput | undefined = options; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } const _options = this._buildAssetOptions({ cardTransformers: this._config.cardTransformers - }, options); - return utils.lexicalToTransformReady(serializedLexical, this.getSiteUrl(), itemPath, _options); + }, finalOptions) as LexicalTransformOptionsInput; + return utils.lexicalToTransformReady(serializedLexical, this.getSiteUrl(), finalItemPath, _options); } - lexicalRelativeToAbsolute(serializedLexical, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + lexicalRelativeToAbsolute(serializedLexical: string, itemPath: string | null | LexicalTransformOptionsInput, options?: LexicalTransformOptionsInput): string { + let finalItemPath: string | null = null; + let finalOptions: LexicalTransformOptionsInput | undefined = options; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } const _options = this._buildAssetOptions({ assetsOnly: false, cardTransformers: this._config.cardTransformers - }, options); - return utils.lexicalRelativeToAbsolute(serializedLexical, this.getSiteUrl(), itemPath, _options); + }, finalOptions) as LexicalTransformOptionsInput; + return utils.lexicalRelativeToAbsolute(serializedLexical, this.getSiteUrl(), finalItemPath, _options); } - lexicalRelativeToTransformReady(serializedLexical, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + lexicalRelativeToTransformReady(serializedLexical: string, itemPath: string | null | LexicalTransformOptionsInput, options?: LexicalTransformOptionsInput): string { + let finalItemPath: string | null = null; + let finalOptions: LexicalTransformOptionsInput | undefined = options; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } const _options = this._buildAssetOptions({ assetsOnly: false, cardTransformers: this._config.cardTransformers - }, options); - return utils.lexicalRelativeToTransformReady(serializedLexical, this.getSiteUrl(), itemPath, _options); + }, finalOptions) as LexicalTransformOptionsInput; + return utils.lexicalRelativeToTransformReady(serializedLexical, this.getSiteUrl(), finalItemPath, _options); } - lexicalAbsoluteToRelative(serializedLexical, options = {}) { + lexicalAbsoluteToRelative(serializedLexical: string, options: LexicalTransformOptionsInput = {}): string { const _options = this._buildAssetOptions({ assetsOnly: false, cardTransformers: this._config.cardTransformers - }, options); + }, options) as LexicalTransformOptionsInput; return utils.lexicalAbsoluteToRelative(serializedLexical, this.getSiteUrl(), _options); } - lexicalAbsoluteToTransformReady(serializedLexical, options = {}) { + lexicalAbsoluteToTransformReady(serializedLexical: string, options: LexicalTransformOptionsInput = {}): string { const _options = this._buildAssetOptions({ assetsOnly: false, cardTransformers: this._config.cardTransformers - }, options); + }, options) as LexicalTransformOptionsInput; return utils.lexicalAbsoluteToTransformReady(serializedLexical, this.getSiteUrl(), _options); } - plaintextToTransformReady(plaintext, options = {}) { + plaintextToTransformReady(plaintext: string, options: Record = {}): string { const _options = this._buildAssetOptions({}, options); - return utils.plaintextToTransformReady(plaintext, this.getSiteUrl(), _options); + return utils.plaintextToTransformReady(plaintext, this.getSiteUrl(), null, _options); } /** @@ -502,7 +644,7 @@ module.exports = class UrlUtils { * @param {string} [context] describing the context for which you need to check a url * @returns {boolean} */ - isSiteUrl(url, context = 'home') { + isSiteUrl(url: URL, context: string = 'home'): boolean { const siteUrl = new URL(this.urlFor(context, true)); if (siteUrl.host === url.host) { if (url.pathname.startsWith(siteUrl.pathname)) { @@ -513,15 +655,15 @@ module.exports = class UrlUtils { return false; } - get isSSL() { + get isSSL(): typeof utils.isSSL { return utils.isSSL; } - get replacePermalink() { + get replacePermalink(): typeof utils.replacePermalink { return utils.replacePermalink; } - get deduplicateDoubleSlashes() { + get deduplicateDoubleSlashes(): typeof utils.deduplicateDoubleSlashes { return utils.deduplicateDoubleSlashes; } @@ -534,20 +676,20 @@ module.exports = class UrlUtils { * But internally the image is located for example in your custom content path: * my-content/another-dir/images/2017/01/02/author.png */ - get STATIC_IMAGE_URL_PREFIX() { + get STATIC_IMAGE_URL_PREFIX(): string { return this._config.staticImageUrlPrefix; } - get STATIC_FILES_URL_PREFIX() { + get STATIC_FILES_URL_PREFIX(): string { return this._config.staticFilesUrlPrefix; } - get STATIC_MEDIA_URL_PREFIX() { + get STATIC_MEDIA_URL_PREFIX(): string { return this._config.staticMediaUrlPrefix; } // expose underlying functions to ease testing - get _utils() { + get _utils(): typeof utils { return utils; } }; diff --git a/packages/url-utils/src/index.ts b/packages/url-utils/src/index.ts new file mode 100644 index 000000000..c866aa608 --- /dev/null +++ b/packages/url-utils/src/index.ts @@ -0,0 +1,3 @@ +import UrlUtils from './UrlUtils'; + +export = UrlUtils; diff --git a/packages/url-utils/src/utils/absolute-to-relative.ts b/packages/url-utils/src/utils/absolute-to-relative.ts index 532c91bd2..f072de19f 100644 --- a/packages/url-utils/src/utils/absolute-to-relative.ts +++ b/packages/url-utils/src/utils/absolute-to-relative.ts @@ -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'); +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; /** * Convert an absolute URL to a root-relative path if it matches the supplied root domain. @@ -13,8 +20,8 @@ const stripSubdirectoryFromPath = require('./strip-subdirectory-from-path'); * @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, @@ -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'); @@ -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; @@ -61,4 +72,4 @@ const absoluteToRelative = function absoluteToRelative(url, rootUrl, _options = return url; }; -module.exports = absoluteToRelative; +export default absoluteToRelative; diff --git a/packages/url-utils/src/utils/absolute-to-transform-ready.ts b/packages/url-utils/src/utils/absolute-to-transform-ready.ts index ef40e6455..b5c172f82 100644 --- a/packages/url-utils/src/utils/absolute-to-transform-ready.ts +++ b/packages/url-utils/src/utils/absolute-to-transform-ready.ts @@ -1,9 +1,20 @@ -// @ts-nocheck -const {URL} = require('url'); -const absoluteToRelative = require('./absolute-to-relative'); +import type {TransformReadyReplacementOptions} from './types'; +import absoluteToRelative, {type AbsoluteToRelativeOptions} from './absolute-to-relative'; +import {URL} from 'url'; -function isRelative(url) { - let parsedInput; +export interface AbsoluteToTransformReadyOptions extends TransformReadyReplacementOptions, AbsoluteToRelativeOptions { + withoutSubdirectory: boolean; + staticFilesUrlPrefix?: string; + staticMediaUrlPrefix?: string; + imageBaseUrl?: string | null; + filesBaseUrl?: string | null; + mediaBaseUrl?: string | null; +} + +export type AbsoluteToTransformReadyOptionsInput = Partial; + +function isRelative(url: string): boolean { + let parsedInput: URL; try { parsedInput = new URL(url, 'http://relative'); } catch (e) { @@ -14,8 +25,12 @@ 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', @@ -23,7 +38,9 @@ const absoluteToTransformReady = function (url, root, _options = {}) { staticMediaUrlPrefix: 'content/media', imageBaseUrl: null, filesBaseUrl: null, - mediaBaseUrl: null + mediaBaseUrl: null, + ignoreProtocol: true, + assetsOnly: false }; const options = Object.assign({}, defaultOptions, _options); @@ -66,4 +83,4 @@ const absoluteToTransformReady = function (url, root, _options = {}) { return url; }; -module.exports = absoluteToTransformReady; +export default absoluteToTransformReady; diff --git a/packages/url-utils/src/utils/build-early-exit-match.ts b/packages/url-utils/src/utils/build-early-exit-match.ts index 078b649dd..e014cd427 100644 --- a/packages/url-utils/src/utils/build-early-exit-match.ts +++ b/packages/url-utils/src/utils/build-early-exit-match.ts @@ -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, @@ -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: string | null | undefined): value is string => typeof value === 'string' && value.length > 0) + .map((value: string) => { let normalized = options.ignoreProtocol ? value.replace(/http:|https:/, '') : value; return normalized.replace(/\/$/, ''); }) - .filter(Boolean) + .filter((value: string): boolean => Boolean(value)) .map(escapeRegExp); if (!candidates.length) { @@ -37,7 +42,7 @@ function buildEarlyExitMatch(siteUrl, options = {}) { return `(?:${candidates.join('|')})`; } -module.exports = { +export default { buildEarlyExitMatch, escapeRegExp }; diff --git a/packages/url-utils/src/utils/deduplicate-double-slashes.ts b/packages/url-utils/src/utils/deduplicate-double-slashes.ts index f6f35ea07..5ad51993a 100644 --- a/packages/url-utils/src/utils/deduplicate-double-slashes.ts +++ b/packages/url-utils/src/utils/deduplicate-double-slashes.ts @@ -1,9 +1,8 @@ -// @ts-nocheck -function deduplicateDoubleSlashes(url) { +function deduplicateDoubleSlashes(url: string): string { // Preserve protocol slashes (e.g., http://, https://) and only deduplicate // slashes in the path portion. The pattern (^|[^:])\/\/+ matches double slashes // that are either at the start of the string or not preceded by a colon. return url.replace(/(^|[^:])\/\/+/g, '$1/'); } -module.exports = deduplicateDoubleSlashes; +export default deduplicateDoubleSlashes; diff --git a/packages/url-utils/src/utils/deduplicate-subdirectory.ts b/packages/url-utils/src/utils/deduplicate-subdirectory.ts index de74b2f17..c6b9c6e84 100644 --- a/packages/url-utils/src/utils/deduplicate-subdirectory.ts +++ b/packages/url-utils/src/utils/deduplicate-subdirectory.ts @@ -1,5 +1,4 @@ -// @ts-nocheck -const {URL} = require('url'); +import {URL} from 'url'; /** * Remove duplicated directories from the start of a path or url's path @@ -8,7 +7,7 @@ const {URL} = require('url'); * @param {string} rootUrl Root URL with an optional subdirectory * @returns {string} URL or pathname with any duplicated subdirectory removed */ -const deduplicateSubdirectory = function deduplicateSubdirectory(url, rootUrl) { +const deduplicateSubdirectory = function deduplicateSubdirectory(url: string, rootUrl: string): string { // force root url to always have a trailing-slash for consistent behaviour if (!rootUrl.endsWith('/')) { rootUrl = `${rootUrl}/`; @@ -29,4 +28,4 @@ const deduplicateSubdirectory = function deduplicateSubdirectory(url, rootUrl) { return url.replace(subdirRegex, `$1${subdir}/`); }; -module.exports = deduplicateSubdirectory; +export default deduplicateSubdirectory; diff --git a/packages/url-utils/src/utils/html-absolute-to-relative.ts b/packages/url-utils/src/utils/html-absolute-to-relative.ts index d083cb4bb..147592570 100644 --- a/packages/url-utils/src/utils/html-absolute-to-relative.ts +++ b/packages/url-utils/src/utils/html-absolute-to-relative.ts @@ -1,21 +1,26 @@ -// @ts-nocheck -const htmlTransform = require('./html-transform'); -const absoluteToRelative = require('./absolute-to-relative'); +import type {HtmlTransformOptionsInput} from './types'; +import type {AbsoluteToRelativeOptionsInput} from './absolute-to-relative'; +import htmlTransform from './html-transform'; +import absoluteToRelative from './absolute-to-relative'; -function htmlAbsoluteToRelative(html = '', siteUrl, _options) { - const defaultOptions = {assetsOnly: false, ignoreProtocol: true}; - const options = Object.assign({}, defaultOptions, _options || {}); +function htmlAbsoluteToRelative( + html: string = '', + siteUrl: string, + _options: AbsoluteToRelativeOptionsInput = {} +): string { + const defaultOptions: AbsoluteToRelativeOptionsInput = {assetsOnly: false, ignoreProtocol: true}; + const options: HtmlTransformOptionsInput = Object.assign({}, defaultOptions, _options || {}); // exit early and avoid parsing if the content does not contain the siteUrl options.earlyExitMatchStr = options.ignoreProtocol ? siteUrl.replace(/http:|https:/, '') : siteUrl; options.earlyExitMatchStr = options.earlyExitMatchStr.replace(/\/$/, ''); // need to ignore itemPath because absoluteToRelative doesn't take that option - const transformFunction = function (_url, _siteUrl, _itemPath, __options) { + const transformFunction = function (_url: string, _siteUrl: string, _itemPath: string | null, __options: AbsoluteToRelativeOptionsInput): string { return absoluteToRelative(_url, _siteUrl, __options); }; return htmlTransform(html, siteUrl, transformFunction, '', options); } -module.exports = htmlAbsoluteToRelative; +export default htmlAbsoluteToRelative; diff --git a/packages/url-utils/src/utils/html-absolute-to-transform-ready.ts b/packages/url-utils/src/utils/html-absolute-to-transform-ready.ts index 3a544bbb4..fe3c89673 100644 --- a/packages/url-utils/src/utils/html-absolute-to-transform-ready.ts +++ b/packages/url-utils/src/utils/html-absolute-to-transform-ready.ts @@ -1,21 +1,29 @@ -// @ts-nocheck -const htmlTransform = require('./html-transform'); -const absoluteToTransformReady = require('./absolute-to-transform-ready'); -const {buildEarlyExitMatch} = require('./build-early-exit-match'); +import type {HtmlTransformOptionsInput, AbsoluteToTransformReadyOptionsInput} from './types'; +import htmlTransform from './html-transform'; +import absoluteToTransformReady from './absolute-to-transform-ready'; +import buildEarlyExitMatchModule from './build-early-exit-match'; +const {buildEarlyExitMatch} = buildEarlyExitMatchModule; -const htmlAbsoluteToTransformReady = function (html = '', siteUrl, _options) { - const defaultOptions = {assetsOnly: false, ignoreProtocol: true}; - const options = Object.assign({}, defaultOptions, _options || {}); +const htmlAbsoluteToTransformReady = function ( + html: string = '', + siteUrl: string, + _options: AbsoluteToTransformReadyOptionsInput = {} +): string { + const defaultOptions: AbsoluteToTransformReadyOptionsInput = {assetsOnly: false, ignoreProtocol: true}; + const options: HtmlTransformOptionsInput = Object.assign({}, defaultOptions, _options || {}); // exit early and avoid parsing if the content does not contain the siteUrl or configured asset bases - options.earlyExitMatchStr = buildEarlyExitMatch(siteUrl, options); + const earlyExitMatch = buildEarlyExitMatch(siteUrl, options); + if (earlyExitMatch) { + options.earlyExitMatchStr = earlyExitMatch; + } // need to ignore itemPath because absoluteToRelative doesn't take that option - const transformFunction = function (_url, _siteUrl, _itemPath, __options) { + const transformFunction = function (_url: string, _siteUrl: string, _itemPath: string | null, __options: AbsoluteToTransformReadyOptionsInput): string { return absoluteToTransformReady(_url, _siteUrl, __options); }; return htmlTransform(html, siteUrl, transformFunction, '', options); }; -module.exports = htmlAbsoluteToTransformReady; +export default htmlAbsoluteToTransformReady; diff --git a/packages/url-utils/src/utils/html-relative-to-absolute.ts b/packages/url-utils/src/utils/html-relative-to-absolute.ts index a275a180b..86d1ea43c 100644 --- a/packages/url-utils/src/utils/html-relative-to-absolute.ts +++ b/packages/url-utils/src/utils/html-relative-to-absolute.ts @@ -1,10 +1,15 @@ -// @ts-nocheck -const htmlTransform = require('./html-transform'); -const relativeToAbsolute = require('./relative-to-absolute'); +import type {HtmlTransformOptionsInput, SecureOptionsInput} from './types'; +import htmlTransform from './html-transform'; +import relativeToAbsolute from './relative-to-absolute'; -function htmlRelativeToAbsolute(html = '', siteUrl, itemPath, _options) { - const defaultOptions = {assetsOnly: false, secure: false}; - const options = Object.assign({}, defaultOptions, _options || {}); +function htmlRelativeToAbsolute( + html: string = '', + siteUrl: string, + itemPath: string | null, + _options: SecureOptionsInput = {} +): string { + const defaultOptions: SecureOptionsInput = {assetsOnly: false, secure: false}; + const options: HtmlTransformOptionsInput = Object.assign({}, defaultOptions, _options || {}); // exit early and avoid parsing if the content does not contain an attribute we might transform options.earlyExitMatchStr = 'href=|src=|srcset='; @@ -15,4 +20,4 @@ function htmlRelativeToAbsolute(html = '', siteUrl, itemPath, _options) { return htmlTransform(html, siteUrl, relativeToAbsolute, itemPath, options); } -module.exports = htmlRelativeToAbsolute; +export default htmlRelativeToAbsolute; diff --git a/packages/url-utils/src/utils/html-relative-to-transform-ready.ts b/packages/url-utils/src/utils/html-relative-to-transform-ready.ts index 9d7d4d71c..c4e9fe9e5 100644 --- a/packages/url-utils/src/utils/html-relative-to-transform-ready.ts +++ b/packages/url-utils/src/utils/html-relative-to-transform-ready.ts @@ -1,21 +1,31 @@ -// @ts-nocheck -const htmlTransform = require('./html-transform'); -const relativeToTransformReady = require('./relative-to-transform-ready'); +import type {HtmlTransformOptionsInput} from './types'; +import htmlTransform from './html-transform'; +import relativeToTransformReady, {type RelativeToTransformReadyOptionsInput as RelativeToTransformReadyOptionsInputType} from './relative-to-transform-ready'; -const htmlRelativeToTransformReady = function (html = '', root, itemPath, _options) { +const htmlRelativeToTransformReady = function ( + html: string = '', + root: string, + itemPath: string | null | RelativeToTransformReadyOptionsInputType, + _options?: RelativeToTransformReadyOptionsInputType +): string { // itemPath is optional, if it's an object may be the options param instead - if (typeof itemPath === 'object' && !_options) { - _options = itemPath; - itemPath = null; + let finalItemPath: string | null = null; + let finalOptions: RelativeToTransformReadyOptionsInputType = _options || {}; + + if (typeof itemPath === 'object' && itemPath !== null && !_options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } - const defaultOptions = { + const defaultOptions: RelativeToTransformReadyOptionsInputType = { replacementStr: '__GHOST_URL__' }; - const overrideOptions = { + const overrideOptions: RelativeToTransformReadyOptionsInputType = { secure: false }; - const options = Object.assign({}, defaultOptions, _options, overrideOptions); + const options: HtmlTransformOptionsInput = Object.assign({}, defaultOptions, finalOptions, overrideOptions); // exit early and avoid parsing if the content does not contain an attribute we might transform options.earlyExitMatchStr = 'href=|src=|srcset='; @@ -23,7 +33,7 @@ const htmlRelativeToTransformReady = function (html = '', root, itemPath, _optio options.earlyExitMatchStr = options.staticImageUrlPrefix; } - return htmlTransform(html, root, relativeToTransformReady, itemPath, options); + return htmlTransform(html, root, relativeToTransformReady, finalItemPath, options); }; -module.exports = htmlRelativeToTransformReady; +export default htmlRelativeToTransformReady; diff --git a/packages/url-utils/src/utils/html-to-transform-ready.ts b/packages/url-utils/src/utils/html-to-transform-ready.ts index e351e04a0..6412d8d3c 100644 --- a/packages/url-utils/src/utils/html-to-transform-ready.ts +++ b/packages/url-utils/src/utils/html-to-transform-ready.ts @@ -1,14 +1,25 @@ -// @ts-nocheck -const htmlRelativeToAbsolute = require('./html-relative-to-absolute'); -const htmlAbsoluteToTransformReady = require('./html-absolute-to-transform-ready'); +import type {HtmlTransformOptionsInput} from './types'; +import htmlRelativeToAbsolute from './html-relative-to-absolute'; +import htmlAbsoluteToTransformReady from './html-absolute-to-transform-ready'; +import type {AbsoluteToTransformReadyOptionsInput} from './absolute-to-transform-ready'; -function htmlToTransformReady(html, siteUrl, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; +function htmlToTransformReady( + html: string, + siteUrl: string, + itemPath: string | null | HtmlTransformOptionsInput, + options?: HtmlTransformOptionsInput +): string { + let finalItemPath: string | null = null; + let finalOptions: HtmlTransformOptionsInput = options || {}; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } - const absolute = htmlRelativeToAbsolute(html, siteUrl, itemPath, options); - return htmlAbsoluteToTransformReady(absolute, siteUrl, options); + const absolute = htmlRelativeToAbsolute(html, siteUrl, finalItemPath, finalOptions); + return htmlAbsoluteToTransformReady(absolute, siteUrl, finalOptions as AbsoluteToTransformReadyOptionsInput); } -module.exports = htmlToTransformReady; +export default htmlToTransformReady; diff --git a/packages/url-utils/src/utils/html-transform.ts b/packages/url-utils/src/utils/html-transform.ts index 3f09919b9..cb4f6dda8 100644 --- a/packages/url-utils/src/utils/html-transform.ts +++ b/packages/url-utils/src/utils/html-transform.ts @@ -1,20 +1,20 @@ -// @ts-nocheck +import type {HtmlTransformOptions, HtmlTransformOptionsInput, UrlTransformFunction} from './types'; const cheerio = require('cheerio'); -function escapeRegExp(string) { +function escapeRegExp(string: string): string { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } -function extractSrcsetUrls(srcset = '') { +function extractSrcsetUrls(srcset: string = ''): string[] { return srcset.split(',').map((part) => { return part.trim().split(/\s+/)[0]; }); } -function extractStyleUrls(style = '') { - const urls = []; +function extractStyleUrls(style: string = ''): string[] { + const urls: string[] = []; const regex = /url\(['|"]([^)]+)['|"]\)/g; - let match; + let match: RegExpExecArray | null; while ((match = regex.exec(style)) !== null) { urls.push(match[1]); @@ -23,9 +23,18 @@ function extractStyleUrls(style = '') { return urls; } -function htmlTransform(html = '', siteUrl, transformFunction, itemPath, _options) { - const defaultOptions = {assetsOnly: false, secure: false}; - const options = Object.assign({}, defaultOptions, _options || {}); +function htmlTransform( + html: string = '', + siteUrl: string, + transformFunction: UrlTransformFunction, + itemPath: string | null, + _options: HtmlTransformOptionsInput = {} +): string { + const defaultOptions: HtmlTransformOptions = { + assetsOnly: false, + secure: false + }; + const options: HtmlTransformOptions = Object.assign({}, defaultOptions, _options || {}); if (!html || (options.earlyExitMatchStr && !html.match(new RegExp(options.earlyExitMatchStr)))) { return html; @@ -43,9 +52,15 @@ function htmlTransform(html = '', siteUrl, transformFunction, itemPath, _options // {name: 'href', originalValue: '/test', absoluteValue: '.../test'}, // ] // } - const replacements = {}; + interface Replacement { + name: string; + originalValue: string; + transformedValue?: string; + skip?: boolean; + } + const replacements: Record = {}; - function addReplacement(replacement) { + function addReplacement(replacement: Replacement): void { const key = `${replacement.name}="${replacement.originalValue}"`; if (!replacements[key]) { @@ -56,10 +71,11 @@ function htmlTransform(html = '', siteUrl, transformFunction, itemPath, _options } // find all of the relative url attributes that we care about - ['href', 'src', 'srcset', 'style'].forEach((attributeName) => { - htmlContent('[' + attributeName + ']').each((ix, el) => { + ['href', 'src', 'srcset', 'style'].forEach((attributeName: string) => { + htmlContent('[' + attributeName + ']').each((ix: number, el: cheerio.Element) => { // ignore elems and html inside of elements - if (el.name === 'stream' || htmlContent(el).closest('code').length) { + const elementName = 'name' in el ? el.name : null; + if (elementName === 'stream' || htmlContent(el).closest('code').length) { addReplacement({ name: attributeName, originalValue: htmlContent(el).attr(attributeName), @@ -68,23 +84,23 @@ function htmlTransform(html = '', siteUrl, transformFunction, itemPath, _options return; } - el = htmlContent(el); - const originalValue = el.attr(attributeName); + const elWrapper = htmlContent(el); + const originalValue = elWrapper.attr(attributeName); if (attributeName === 'srcset' || attributeName === 'style') { - let urls; + let urls: string[]; if (attributeName === 'srcset') { urls = extractSrcsetUrls(originalValue); } else { urls = extractStyleUrls(originalValue); } - const absoluteUrls = urls.map(url => transformFunction(url, siteUrl, itemPath, options)); + const absoluteUrls = urls.map((url: string) => transformFunction(url, siteUrl, itemPath, options)); let transformedValue = originalValue; - urls.forEach((url, i) => { + urls.forEach((url: string, i: number) => { if (absoluteUrls[i]) { - let regex = new RegExp(escapeRegExp(url), 'g'); + const regex = new RegExp(escapeRegExp(url), 'g'); transformedValue = transformedValue.replace(regex, absoluteUrls[i]); } }); @@ -121,6 +137,12 @@ function htmlTransform(html = '', siteUrl, transformFunction, itemPath, _options return; } + // transformedValue is guaranteed to exist here because we only add replacements + // when transformedValue !== originalValue, and we've already skipped entries with skip: true + if (!transformedValue) { + return; + } + // this regex avoids matching unrelated plain text by checking that the attribute/value pair // is surrounded by <> - that should be sufficient because if the plain text had that wrapper // it would be parsed as a tag @@ -128,7 +150,7 @@ function htmlTransform(html = '', siteUrl, transformFunction, itemPath, _options const regex = new RegExp(`<[a-zA-Z][^>]*?(${name}=['"](${escapeRegExp(originalValue)})['"]).*?>`, 'gs'); let matchCount = 0; - html = html.replace(regex, (match, p1) => { + html = html.replace(regex, (match: string, p1: string): string => { let result = match; if (matchCount === skipCount) { result = match.replace(p1, p1.replace(originalValue, transformedValue)); @@ -142,4 +164,4 @@ function htmlTransform(html = '', siteUrl, transformFunction, itemPath, _options return html; } -module.exports = htmlTransform; +export default htmlTransform; diff --git a/packages/url-utils/src/utils/index.ts b/packages/url-utils/src/utils/index.ts index a297f9213..8498d6503 100644 --- a/packages/url-utils/src/utils/index.ts +++ b/packages/url-utils/src/utils/index.ts @@ -1,39 +1,116 @@ -// @ts-nocheck -module.exports = { - absoluteToRelative: require('./absolute-to-relative'), - absoluteToTransformReady: require('./absolute-to-transform-ready'), - deduplicateDoubleSlashes: require('./deduplicate-double-slashes'), - deduplicateSubdirectory: require('./deduplicate-subdirectory'), - htmlAbsoluteToRelative: require('./html-absolute-to-relative'), - htmlRelativeToAbsolute: require('./html-relative-to-absolute'), - htmlAbsoluteToTransformReady: require('./html-absolute-to-transform-ready'), - htmlRelativeToTransformReady: require('./html-relative-to-transform-ready'), - htmlToTransformReady: require('./html-to-transform-ready'), - isSSL: require('./is-ssl'), - markdownAbsoluteToRelative: require('./markdown-absolute-to-relative'), - markdownRelativeToAbsolute: require('./markdown-relative-to-absolute'), - markdownAbsoluteToTransformReady: require('./markdown-absolute-to-transform-ready'), - markdownRelativeToTransformReady: require('./markdown-relative-to-transform-ready'), - markdownToTransformReady: require('./markdown-to-transform-ready'), - mobiledocAbsoluteToRelative: require('./mobiledoc-absolute-to-relative'), - mobiledocRelativeToAbsolute: require('./mobiledoc-relative-to-absolute'), - mobiledocAbsoluteToTransformReady: require('./mobiledoc-absolute-to-transform-ready'), - mobiledocRelativeToTransformReady: require('./mobiledoc-relative-to-transform-ready'), - mobiledocToTransformReady: require('./mobiledoc-to-transform-ready'), - lexicalAbsoluteToRelative: require('./lexical-absolute-to-relative'), - lexicalRelativeToAbsolute: require('./lexical-relative-to-absolute'), - lexicalAbsoluteToTransformReady: require('./lexical-absolute-to-transform-ready'), - lexicalRelativeToTransformReady: require('./lexical-relative-to-transform-ready'), - lexicalToTransformReady: require('./lexical-to-transform-ready'), - 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'), - replacePermalink: require('./replace-permalink'), - stripSubdirectoryFromPath: require('./strip-subdirectory-from-path'), - toTransformReady: require('./to-transform-ready'), - transformReadyToAbsolute: require('./transform-ready-to-absolute'), - transformReadyToRelative: require('./transform-ready-to-relative'), - urlJoin: require('./url-join') +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 htmlAbsoluteToRelative from './html-absolute-to-relative'; +import htmlAbsoluteToTransformReady from './html-absolute-to-transform-ready'; +import htmlRelativeToAbsolute from './html-relative-to-absolute'; +import htmlRelativeToTransformReady from './html-relative-to-transform-ready'; +import htmlToTransformReady from './html-to-transform-ready'; +import isSSL from './is-ssl'; +import lexicalAbsoluteToRelative from './lexical-absolute-to-relative'; +import lexicalAbsoluteToTransformReady from './lexical-absolute-to-transform-ready'; +import lexicalRelativeToAbsolute from './lexical-relative-to-absolute'; +import lexicalRelativeToTransformReady from './lexical-relative-to-transform-ready'; +import lexicalToTransformReady from './lexical-to-transform-ready'; +import markdownAbsoluteToRelative from './markdown-absolute-to-relative'; +import markdownRelativeToAbsolute from './markdown-relative-to-absolute'; +import markdownAbsoluteToTransformReady from './markdown-absolute-to-transform-ready'; +import markdownRelativeToTransformReady from './markdown-relative-to-transform-ready'; +import markdownToTransformReady from './markdown-to-transform-ready'; +import mobiledocAbsoluteToRelative from './mobiledoc-absolute-to-relative'; +import mobiledocRelativeToAbsolute from './mobiledoc-relative-to-absolute'; +import mobiledocAbsoluteToTransformReady from './mobiledoc-absolute-to-transform-ready'; +import mobiledocRelativeToTransformReady from './mobiledoc-relative-to-transform-ready'; +import mobiledocToTransformReady from './mobiledoc-to-transform-ready'; +import plaintextAbsoluteToTransformReady from './plaintext-absolute-to-transform-ready'; +import plaintextRelativeToTransformReady from './plaintext-relative-to-transform-ready'; +import plaintextToTransformReady from './plaintext-to-transform-ready'; +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'; + +export { + absoluteToRelative, + absoluteToTransformReady, + deduplicateDoubleSlashes, + deduplicateSubdirectory, + htmlAbsoluteToRelative, + htmlRelativeToAbsolute, + htmlAbsoluteToTransformReady, + htmlRelativeToTransformReady, + htmlToTransformReady, + isSSL, + lexicalAbsoluteToRelative, + lexicalAbsoluteToTransformReady, + lexicalRelativeToAbsolute, + lexicalRelativeToTransformReady, + lexicalToTransformReady, + markdownAbsoluteToRelative, + markdownRelativeToAbsolute, + markdownAbsoluteToTransformReady, + markdownRelativeToTransformReady, + markdownToTransformReady, + mobiledocAbsoluteToRelative, + mobiledocRelativeToAbsolute, + mobiledocAbsoluteToTransformReady, + mobiledocRelativeToTransformReady, + mobiledocToTransformReady, + plaintextAbsoluteToTransformReady, + plaintextRelativeToTransformReady, + plaintextToTransformReady, + relativeToAbsolute, + relativeToTransformReady, + replacePermalink, + stripSubdirectoryFromPath, + toTransformReady, + transformReadyToAbsolute, + transformReadyToRelative, + urlJoin }; + +const utils = { + absoluteToRelative, + absoluteToTransformReady, + deduplicateDoubleSlashes, + deduplicateSubdirectory, + htmlAbsoluteToRelative, + htmlRelativeToAbsolute, + htmlAbsoluteToTransformReady, + htmlRelativeToTransformReady, + htmlToTransformReady, + isSSL, + lexicalAbsoluteToRelative, + lexicalRelativeToAbsolute, + lexicalAbsoluteToTransformReady, + lexicalRelativeToTransformReady, + lexicalToTransformReady, + markdownAbsoluteToRelative, + markdownAbsoluteToTransformReady, + markdownRelativeToAbsolute, + markdownRelativeToTransformReady, + markdownToTransformReady, + mobiledocAbsoluteToRelative, + mobiledocAbsoluteToTransformReady, + mobiledocRelativeToAbsolute, + mobiledocRelativeToTransformReady, + mobiledocToTransformReady, + plaintextAbsoluteToTransformReady, + plaintextRelativeToTransformReady, + plaintextToTransformReady, + relativeToAbsolute, + relativeToTransformReady, + replacePermalink, + stripSubdirectoryFromPath, + toTransformReady, + transformReadyToAbsolute, + transformReadyToRelative, + urlJoin +}; + +export default utils; diff --git a/packages/url-utils/src/utils/is-ssl.ts b/packages/url-utils/src/utils/is-ssl.ts index 5ddaefe35..e4edee372 100644 --- a/packages/url-utils/src/utils/is-ssl.ts +++ b/packages/url-utils/src/utils/is-ssl.ts @@ -1,10 +1,9 @@ -// @ts-nocheck // require the whatwg compatible URL library (same behaviour in node and browser) -const {URL} = require('url'); +import {URL} from 'url'; -function isSSL(urlToParse) { +function isSSL(urlToParse: string): boolean { const {protocol} = new URL(urlToParse); return protocol === 'https:'; } -module.exports = isSSL; +export default isSSL; diff --git a/packages/url-utils/src/utils/lexical-absolute-to-relative.ts b/packages/url-utils/src/utils/lexical-absolute-to-relative.ts index 97635c750..4e8a71d83 100644 --- a/packages/url-utils/src/utils/lexical-absolute-to-relative.ts +++ b/packages/url-utils/src/utils/lexical-absolute-to-relative.ts @@ -1,17 +1,21 @@ -// @ts-nocheck -const absoluteToRelative = require('./absolute-to-relative'); -const lexicalTransform = require('./lexical-transform'); +import type {LexicalTransformOptionsInput} from './types'; +import absoluteToRelative, {type AbsoluteToRelativeOptionsInput} from './absolute-to-relative'; +import lexicalTransform from './lexical-transform'; -function lexicalAbsoluteToRelative(serializedLexical, siteUrl, _options = {}) { - const defaultOptions = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; - const overrideOptions = {siteUrl, transformType: 'absoluteToRelative'}; +function lexicalAbsoluteToRelative( + serializedLexical: string, + siteUrl: string, + _options: LexicalTransformOptionsInput = {} +): string { + const defaultOptions: LexicalTransformOptionsInput = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; + const overrideOptions: LexicalTransformOptionsInput = {siteUrl, transformType: 'absoluteToRelative'}; const options = Object.assign({}, defaultOptions, _options, overrideOptions); - const transformFunction = function (_url, _siteUrl, _itemPath, __options) { + const transformFunction = function (_url: string, _siteUrl: string, _itemPath: string | null, __options: AbsoluteToRelativeOptionsInput): string { return absoluteToRelative(_url, _siteUrl, __options); }; return lexicalTransform(serializedLexical, siteUrl, transformFunction, '', options); } -module.exports = lexicalAbsoluteToRelative; +export default lexicalAbsoluteToRelative; diff --git a/packages/url-utils/src/utils/lexical-absolute-to-transform-ready.ts b/packages/url-utils/src/utils/lexical-absolute-to-transform-ready.ts index 54817fb8f..a4c21abb8 100644 --- a/packages/url-utils/src/utils/lexical-absolute-to-transform-ready.ts +++ b/packages/url-utils/src/utils/lexical-absolute-to-transform-ready.ts @@ -1,17 +1,21 @@ -// @ts-nocheck -const absoluteToTransformReady = require('./absolute-to-transform-ready'); -const lexicalTransform = require('./lexical-transform'); +import type {LexicalTransformOptionsInput, AbsoluteToTransformReadyOptionsInput} from './types'; +import absoluteToTransformReady from './absolute-to-transform-ready'; +import lexicalTransform from './lexical-transform'; -function lexicalAbsoluteToRelative(serializedLexical, siteUrl, _options = {}) { - const defaultOptions = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; - const overrideOptions = {siteUrl, transformType: 'toTransformReady'}; +function lexicalAbsoluteToTransformReady( + serializedLexical: string, + siteUrl: string, + _options: LexicalTransformOptionsInput = {} +): string { + const defaultOptions: LexicalTransformOptionsInput = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; + const overrideOptions: LexicalTransformOptionsInput = {siteUrl, transformType: 'toTransformReady'}; const options = Object.assign({}, defaultOptions, _options, overrideOptions); - const transformFunction = function (_url, _siteUrl, _itemPath, __options) { + const transformFunction = function (_url: string, _siteUrl: string, _itemPath: string | null, __options: AbsoluteToTransformReadyOptionsInput): string { return absoluteToTransformReady(_url, _siteUrl, __options); }; return lexicalTransform(serializedLexical, siteUrl, transformFunction, '', options); } -module.exports = lexicalAbsoluteToRelative; +export default lexicalAbsoluteToTransformReady; diff --git a/packages/url-utils/src/utils/lexical-relative-to-absolute.ts b/packages/url-utils/src/utils/lexical-relative-to-absolute.ts index bd6aa3bf8..a1a40722b 100644 --- a/packages/url-utils/src/utils/lexical-relative-to-absolute.ts +++ b/packages/url-utils/src/utils/lexical-relative-to-absolute.ts @@ -1,13 +1,18 @@ -// @ts-nocheck -const relativeToAbsolute = require('./relative-to-absolute'); -const lexicalTransform = require('./lexical-transform'); +import type {LexicalTransformOptionsInput} from './types'; +import relativeToAbsolute from './relative-to-absolute'; +import lexicalTransform from './lexical-transform'; -function lexicalRelativeToAbsolute(serializedLexical, siteUrl, itemPath, _options = {}) { - const defaultOptions = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; - const overrideOptions = {siteUrl, itemPath, transformType: 'relativeToAbsolute'}; +function lexicalRelativeToAbsolute( + serializedLexical: string, + siteUrl: string, + itemPath: string | null, + _options: LexicalTransformOptionsInput = {} +): string { + const defaultOptions: LexicalTransformOptionsInput = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; + const overrideOptions: LexicalTransformOptionsInput = {siteUrl, itemPath, transformType: 'relativeToAbsolute'}; const options = Object.assign({}, defaultOptions, _options, overrideOptions); return lexicalTransform(serializedLexical, siteUrl, relativeToAbsolute, itemPath, options); } -module.exports = lexicalRelativeToAbsolute; +export default lexicalRelativeToAbsolute; diff --git a/packages/url-utils/src/utils/lexical-relative-to-transform-ready.ts b/packages/url-utils/src/utils/lexical-relative-to-transform-ready.ts index 25ad6089e..c23792573 100644 --- a/packages/url-utils/src/utils/lexical-relative-to-transform-ready.ts +++ b/packages/url-utils/src/utils/lexical-relative-to-transform-ready.ts @@ -1,13 +1,18 @@ -// @ts-nocheck -const relativeToTransformReady = require('./relative-to-transform-ready'); -const lexicalTransform = require('./lexical-transform'); +import type {LexicalTransformOptionsInput} from './types'; +import relativeToTransformReady from './relative-to-transform-ready'; +import lexicalTransform from './lexical-transform'; -function lexicalRelativeToTransformReady(serializedLexical, siteUrl, itemPath, _options = {}) { - const defaultOptions = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; - const overrideOptions = {siteUrl, transformType: 'toTransformReady'}; +function lexicalRelativeToTransformReady( + serializedLexical: string, + siteUrl: string, + itemPath: string | null, + _options: LexicalTransformOptionsInput = {} +): string { + const defaultOptions: LexicalTransformOptionsInput = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; + const overrideOptions: LexicalTransformOptionsInput = {siteUrl, transformType: 'toTransformReady'}; const options = Object.assign({}, defaultOptions, _options, overrideOptions); return lexicalTransform(serializedLexical, siteUrl, relativeToTransformReady, itemPath, options); } -module.exports = lexicalRelativeToTransformReady; +export default lexicalRelativeToTransformReady; diff --git a/packages/url-utils/src/utils/lexical-to-transform-ready.ts b/packages/url-utils/src/utils/lexical-to-transform-ready.ts index 03180552c..c425e024b 100644 --- a/packages/url-utils/src/utils/lexical-to-transform-ready.ts +++ b/packages/url-utils/src/utils/lexical-to-transform-ready.ts @@ -1,14 +1,24 @@ -// @ts-nocheck -const lexicalRelativeToAbsolute = require('./lexical-relative-to-absolute'); -const lexicalAbsoluteToTransformReady = require('./lexical-absolute-to-transform-ready'); +import type {LexicalTransformOptionsInput} from './types'; +import lexicalRelativeToAbsolute from './lexical-relative-to-absolute'; +import lexicalAbsoluteToTransformReady from './lexical-absolute-to-transform-ready'; -function lexicalToTransformReady(lexical, siteUrl, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; +function lexicalToTransformReady( + lexical: string, + siteUrl: string, + itemPath: string | null | LexicalTransformOptionsInput, + options?: LexicalTransformOptionsInput +): string { + let finalItemPath: string | null = null; + let finalOptions: LexicalTransformOptionsInput = options || {}; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } - const absolute = lexicalRelativeToAbsolute(lexical, siteUrl, itemPath, options); - return lexicalAbsoluteToTransformReady(absolute, siteUrl, options); + const absolute = lexicalRelativeToAbsolute(lexical, siteUrl, finalItemPath, finalOptions); + return lexicalAbsoluteToTransformReady(absolute, siteUrl, finalOptions); } -module.exports = lexicalToTransformReady; +export default lexicalToTransformReady; diff --git a/packages/url-utils/src/utils/lexical-transform.ts b/packages/url-utils/src/utils/lexical-transform.ts index a38f2b28a..497487998 100644 --- a/packages/url-utils/src/utils/lexical-transform.ts +++ b/packages/url-utils/src/utils/lexical-transform.ts @@ -1,4 +1,4 @@ -// @ts-nocheck +import type {LexicalTransformOptions, LexicalTransformOptionsInput, LexicalUrlTransformMap, UrlTransformFunction} from './types'; const _ = require('lodash'); // options.transformMap = { @@ -9,9 +9,28 @@ const _ = require('lodash'); // } // options.transformType = 'relativeToAbsolute' -function lexicalTransform(serializedLexical, siteUrl, transformFunction, itemPath, _options = {}) { - const defaultOptions = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; - const options = Object.assign({}, defaultOptions, _options, {siteUrl, itemPath}); +interface LexicalNode { + type?: string; + url?: string; + children?: LexicalNode[]; + [key: string]: unknown; +} + +interface LexicalDocument { + root?: { + children?: LexicalNode[]; + }; +} + +function lexicalTransform( + serializedLexical: string, + siteUrl: string, + transformFunction: UrlTransformFunction, + itemPath: string | null, + _options: LexicalTransformOptionsInput = {} +): string { + const defaultOptions: LexicalTransformOptionsInput = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; + const options: LexicalTransformOptions = Object.assign({}, defaultOptions, _options, {siteUrl, itemPath}) as LexicalTransformOptions; if (!serializedLexical) { return serializedLexical; @@ -19,7 +38,7 @@ function lexicalTransform(serializedLexical, siteUrl, transformFunction, itemPat // function only accepts serialized lexical so there's no chance of accidentally // modifying pass-by-reference objects - const lexical = JSON.parse(serializedLexical); + const lexical: LexicalDocument = JSON.parse(serializedLexical); if (!lexical?.root?.children) { return serializedLexical; @@ -27,40 +46,49 @@ function lexicalTransform(serializedLexical, siteUrl, transformFunction, itemPat // create a map of node types to urlTransformMap objects // e.g. {'image': {src: 'url', caption: 'html'} - const nodeMap = new Map(); + const nodeMap = new Map(); options.nodes.forEach(node => node.urlTransformMap && nodeMap.set(node.getType(), node.urlTransformMap)); - const transformProperty = function (obj, propertyPath, transform) { + const transformProperty = function (obj: LexicalNode, propertyPath: string, transform: string | LexicalUrlTransformMap): void { const propertyValue = _.get(obj, propertyPath); if (Array.isArray(propertyValue)) { - propertyValue.forEach((item) => { + propertyValue.forEach((item: LexicalNode) => { // arrays of objects need to be defined as a nested object in the urlTransformMap // so the `transform` value is that nested object - Object.entries(transform).forEach(([itemPropertyPath, itemTransform]) => { - transformProperty(item, itemPropertyPath, itemTransform); - }); + if (typeof transform === 'object') { + Object.entries(transform).forEach(([itemPropertyPath, itemTransform]) => { + transformProperty(item, itemPropertyPath, itemTransform); + }); + } }); return; } - if (propertyValue) { - _.set(obj, propertyPath, options.transformMap[options.transformType][transform](propertyValue)); + if (propertyValue && typeof transform === 'string') { + const transformType = options.transformType; + const transformRegistry = options.transformMap[transformType]; + if (transformRegistry && transformRegistry[transform]) { + _.set(obj, propertyPath, transformRegistry[transform](propertyValue as string)); + } } }; // recursively walk the Lexical node tree transforming any card data properties and links - const transformChildren = function (children) { + const transformChildren = function (children: LexicalNode[]): void { for (const child of children) { const isCard = child.type && nodeMap.has(child.type); const isLink = !!child.url; - if (isCard) { - Object.entries(nodeMap.get(child.type)).forEach(([propertyPath, transform]) => { - transformProperty(child, propertyPath, transform); - }); - } else if (isLink) { + if (isCard && child.type) { + const urlTransformMap = nodeMap.get(child.type); + if (urlTransformMap) { + Object.entries(urlTransformMap).forEach(([propertyPath, transform]) => { + transformProperty(child, propertyPath, transform); + }); + } + } else if (isLink && child.url) { child.url = transformFunction(child.url, siteUrl, itemPath, options); } @@ -75,4 +103,4 @@ function lexicalTransform(serializedLexical, siteUrl, transformFunction, itemPat return JSON.stringify(lexical); } -module.exports = lexicalTransform; +export default lexicalTransform; diff --git a/packages/url-utils/src/utils/markdown-absolute-to-relative.ts b/packages/url-utils/src/utils/markdown-absolute-to-relative.ts index a4b1ca6dd..863db7358 100644 --- a/packages/url-utils/src/utils/markdown-absolute-to-relative.ts +++ b/packages/url-utils/src/utils/markdown-absolute-to-relative.ts @@ -1,21 +1,26 @@ -// @ts-nocheck -const markdownTransform = require('./markdown-transform'); -const absoluteToRelative = require('./absolute-to-relative'); -const htmlAbsoluteToRelative = require('./html-absolute-to-relative'); +import type {MarkdownTransformOptionsInput} from './types'; +import type {AbsoluteToRelativeOptionsInput} from './absolute-to-relative'; +import markdownTransform from './markdown-transform'; +import absoluteToRelative from './absolute-to-relative'; +import htmlAbsoluteToRelative from './html-absolute-to-relative'; -function markdownAbsoluteToRelative(markdown = '', siteUrl, _options = {}) { - const defaultOptions = {assetsOnly: false, ignoreProtocol: true}; - const options = Object.assign({}, defaultOptions, _options); +function markdownAbsoluteToRelative( + markdown: string = '', + siteUrl: string, + _options: AbsoluteToRelativeOptionsInput = {} +): string { + const defaultOptions: AbsoluteToRelativeOptionsInput = {assetsOnly: false, ignoreProtocol: true}; + const options: MarkdownTransformOptionsInput = Object.assign({}, defaultOptions, _options); options.earlyExitMatchStr = options.ignoreProtocol ? siteUrl.replace(/http:|https:/, '') : siteUrl; options.earlyExitMatchStr = options.earlyExitMatchStr.replace(/\/$/, ''); // need to ignore itemPath because absoluteToRelative functions doen't take that option const transformFunctions = { - html(_url, _siteUrl, _itemPath, __options) { + html(_url: string, _siteUrl: string, _itemPath: string | null, __options: AbsoluteToRelativeOptionsInput): string { return htmlAbsoluteToRelative(_url, _siteUrl, __options); }, - url(_url, _siteUrl, _itemPath, __options) { + url(_url: string, _siteUrl: string, _itemPath: string | null, __options: AbsoluteToRelativeOptionsInput): string { return absoluteToRelative(_url, _siteUrl, __options); } }; @@ -23,4 +28,4 @@ function markdownAbsoluteToRelative(markdown = '', siteUrl, _options = {}) { return markdownTransform(markdown, siteUrl, transformFunctions, '', options); } -module.exports = markdownAbsoluteToRelative; +export default markdownAbsoluteToRelative; diff --git a/packages/url-utils/src/utils/markdown-absolute-to-transform-ready.ts b/packages/url-utils/src/utils/markdown-absolute-to-transform-ready.ts index a4b77016f..1b189f824 100644 --- a/packages/url-utils/src/utils/markdown-absolute-to-transform-ready.ts +++ b/packages/url-utils/src/utils/markdown-absolute-to-transform-ready.ts @@ -1,21 +1,29 @@ -// @ts-nocheck -const markdownTransform = require('./markdown-transform'); -const absoluteToTransformReady = require('./absolute-to-transform-ready'); -const htmlAbsoluteToTransformReady = require('./html-absolute-to-transform-ready'); -const {buildEarlyExitMatch} = require('./build-early-exit-match'); +import type {MarkdownTransformOptionsInput, AbsoluteToTransformReadyOptionsInput} from './types'; +import markdownTransform from './markdown-transform'; +import absoluteToTransformReady from './absolute-to-transform-ready'; +import htmlAbsoluteToTransformReady from './html-absolute-to-transform-ready'; +import buildEarlyExitMatchModule from './build-early-exit-match'; +const {buildEarlyExitMatch} = buildEarlyExitMatchModule; -function markdownAbsoluteToTransformReady(markdown = '', siteUrl, _options = {}) { - const defaultOptions = {assetsOnly: false, ignoreProtocol: true}; - const options = Object.assign({}, defaultOptions, _options); +function markdownAbsoluteToTransformReady( + markdown: string = '', + siteUrl: string, + _options: AbsoluteToTransformReadyOptionsInput = {} +): string { + const defaultOptions: AbsoluteToTransformReadyOptionsInput = {assetsOnly: false, ignoreProtocol: true}; + const options: MarkdownTransformOptionsInput = Object.assign({}, defaultOptions, _options); - options.earlyExitMatchStr = buildEarlyExitMatch(siteUrl, options); + const earlyExitMatch = buildEarlyExitMatch(siteUrl, options); + if (earlyExitMatch) { + options.earlyExitMatchStr = earlyExitMatch; + } // need to ignore itemPath because absoluteToTransformReady functions doen't take that option const transformFunctions = { - html(_url, _siteUrl, _itemPath, __options) { + html(_url: string, _siteUrl: string, _itemPath: string | null, __options: AbsoluteToTransformReadyOptionsInput): string { return htmlAbsoluteToTransformReady(_url, _siteUrl, __options); }, - url(_url, _siteUrl, _itemPath, __options) { + url(_url: string, _siteUrl: string, _itemPath: string | null, __options: AbsoluteToTransformReadyOptionsInput): string { return absoluteToTransformReady(_url, _siteUrl, __options); } }; @@ -23,4 +31,4 @@ function markdownAbsoluteToTransformReady(markdown = '', siteUrl, _options = {}) return markdownTransform(markdown, siteUrl, transformFunctions, '', options); } -module.exports = markdownAbsoluteToTransformReady; +export default markdownAbsoluteToTransformReady; diff --git a/packages/url-utils/src/utils/markdown-relative-to-absolute.ts b/packages/url-utils/src/utils/markdown-relative-to-absolute.ts index e93846ef0..865bf51fd 100644 --- a/packages/url-utils/src/utils/markdown-relative-to-absolute.ts +++ b/packages/url-utils/src/utils/markdown-relative-to-absolute.ts @@ -1,11 +1,17 @@ -// @ts-nocheck -const markdownTransform = require('./markdown-transform'); -const htmlRelativeToAbsolute = require('./html-relative-to-absolute'); -const relativeToAbsolute = require('./relative-to-absolute'); +import type {MarkdownTransformOptionsInput} from './types'; +import type {SecureOptionsInput} from './types'; +import markdownTransform from './markdown-transform'; +import htmlRelativeToAbsolute from './html-relative-to-absolute'; +import relativeToAbsolute from './relative-to-absolute'; -function markdownRelativeToAbsolute(markdown = '', siteUrl, itemPath, _options = {}) { - const defaultOptions = {assetsOnly: false}; - const options = Object.assign({}, defaultOptions, _options); +function markdownRelativeToAbsolute( + markdown: string = '', + siteUrl: string, + itemPath: string | null, + _options: SecureOptionsInput = {} +): string { + const defaultOptions: SecureOptionsInput = {assetsOnly: false}; + const options: MarkdownTransformOptionsInput = Object.assign({}, defaultOptions, _options); options.earlyExitMatchStr = '\\]\\([^\\s\\)]|href=|src=|srcset='; if (options.assetsOnly) { @@ -20,4 +26,4 @@ function markdownRelativeToAbsolute(markdown = '', siteUrl, itemPath, _options = return markdownTransform(markdown, siteUrl, transformFunctions, itemPath, options); } -module.exports = markdownRelativeToAbsolute; +export default markdownRelativeToAbsolute; diff --git a/packages/url-utils/src/utils/markdown-relative-to-transform-ready.ts b/packages/url-utils/src/utils/markdown-relative-to-transform-ready.ts index 077655cb1..0c8415ead 100644 --- a/packages/url-utils/src/utils/markdown-relative-to-transform-ready.ts +++ b/packages/url-utils/src/utils/markdown-relative-to-transform-ready.ts @@ -1,11 +1,16 @@ -// @ts-nocheck -const markdownTransform = require('./markdown-transform'); -const htmlRelativeToTransformReady = require('./html-relative-to-transform-ready'); -const relativeToTransformReady = require('./relative-to-transform-ready'); +import type {MarkdownTransformOptionsInput, SecureOptionsInput} from './types'; +import markdownTransform from './markdown-transform'; +import htmlRelativeToTransformReady from './html-relative-to-transform-ready'; +import relativeToTransformReady from './relative-to-transform-ready'; -function markdownRelativeToTransformReady(markdown = '', siteUrl, itemPath, _options = {}) { - const defaultOptions = {assetsOnly: false}; - const options = Object.assign({}, defaultOptions, _options); +function markdownRelativeToTransformReady( + markdown: string = '', + siteUrl: string, + itemPath: string | null, + _options: SecureOptionsInput = {} +): string { + const defaultOptions: SecureOptionsInput = {assetsOnly: false}; + const options: MarkdownTransformOptionsInput = Object.assign({}, defaultOptions, _options); options.earlyExitMatchStr = '\\]\\([^\\s\\)]|href=|src=|srcset='; if (options.assetsOnly) { @@ -20,4 +25,4 @@ function markdownRelativeToTransformReady(markdown = '', siteUrl, itemPath, _opt return markdownTransform(markdown, siteUrl, transformFunctions, itemPath, options); } -module.exports = markdownRelativeToTransformReady; +export default markdownRelativeToTransformReady; diff --git a/packages/url-utils/src/utils/markdown-to-transform-ready.ts b/packages/url-utils/src/utils/markdown-to-transform-ready.ts index ed0e74d7f..c8c10d984 100644 --- a/packages/url-utils/src/utils/markdown-to-transform-ready.ts +++ b/packages/url-utils/src/utils/markdown-to-transform-ready.ts @@ -1,14 +1,25 @@ -// @ts-nocheck -const markdownRelativeToAbsolute = require('./markdown-relative-to-absolute'); -const markdownAbsoluteToTransformReady = require('./markdown-absolute-to-transform-ready'); - -function markdownToTransformReady(markdown, siteUrl, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; +import type {MarkdownTransformOptionsInput} from './types'; +import markdownRelativeToAbsolute from './markdown-relative-to-absolute'; +import markdownAbsoluteToTransformReady from './markdown-absolute-to-transform-ready'; + +function markdownToTransformReady( + markdown: string, + siteUrl: string, + itemPath: string | null | MarkdownTransformOptionsInput, + options?: MarkdownTransformOptionsInput +): string { + let finalItemPath: string | null = null; + let finalOptions: MarkdownTransformOptionsInput = options || {}; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } - const absolute = markdownRelativeToAbsolute(markdown, siteUrl, itemPath, options); - return markdownAbsoluteToTransformReady(absolute, siteUrl, options); + + const absolute = markdownRelativeToAbsolute(markdown, siteUrl, finalItemPath, finalOptions); + return markdownAbsoluteToTransformReady(absolute, siteUrl, finalOptions); } -module.exports = markdownToTransformReady; +export default markdownToTransformReady; diff --git a/packages/url-utils/src/utils/markdown-transform.ts b/packages/url-utils/src/utils/markdown-transform.ts index 201dd547d..333db558e 100644 --- a/packages/url-utils/src/utils/markdown-transform.ts +++ b/packages/url-utils/src/utils/markdown-transform.ts @@ -1,9 +1,9 @@ -// @ts-nocheck -let remark; +import type {MarkdownTransformOptions, MarkdownTransformOptionsInput, MarkdownTransformFunctions} from './types'; +let remark: typeof import('remark') | undefined; const footnotes = require('remark-footnotes'); const visit = require('unist-util-visit'); -function replaceLast(find, replace, str) { +function replaceLast(find: string, replace: string, str: string): string { const lastIndex = str.lastIndexOf(find); if (lastIndex === -1) { @@ -16,29 +16,46 @@ function replaceLast(find, replace, str) { return begin + replace + end; } -function markdownTransform(markdown = '', siteUrl, transformFunctions, itemPath, _options = {}) { - const defaultOptions = {assetsOnly: false, ignoreProtocol: true}; - const options = Object.assign({}, defaultOptions, _options); +interface Replacement { + old: string; + new: string; + start: number; + end: number; +} + +function markdownTransform( + markdown: string = '', + siteUrl: string, + transformFunctions: MarkdownTransformFunctions, + itemPath: string | null, + _options: MarkdownTransformOptionsInput = {} +): string { + const defaultOptions: MarkdownTransformOptions = {assetsOnly: false, ignoreProtocol: true}; + const options: MarkdownTransformOptions = Object.assign({}, defaultOptions, _options); if (!markdown || (options.earlyExitMatchStr && !markdown.match(new RegExp(options.earlyExitMatchStr)))) { return markdown; } - const replacements = []; + const replacements: Replacement[] = []; if (!remark) { remark = require('remark'); } + if (!remark) { + return markdown; + } + const tree = remark() .use({settings: {commonmark: true}}) .use(footnotes, {inlineNotes: true}) .parse(markdown); - visit(tree, ['link', 'image', 'html'], (node) => { - if (node.type === 'html' && node.value.match(/src|srcset|href/)) { + visit(tree, ['link', 'image', 'html'], (node: {type: string; value?: string; url?: string; position?: {start: {offset: number}; end: {offset: number}}}) => { + if (node.type === 'html' && node.value && node.value.match(/src|srcset|href/) && node.position) { const oldValue = node.value; - const newValue = transformFunctions.html(node.value, siteUrl, itemPath, options); + const newValue = transformFunctions.html(oldValue, siteUrl, itemPath, options); if (newValue !== oldValue) { replacements.push({ @@ -50,9 +67,9 @@ function markdownTransform(markdown = '', siteUrl, transformFunctions, itemPath, } } - if (node.type === 'link' || node.type === 'image') { + if ((node.type === 'link' || node.type === 'image') && node.url && node.position) { const oldValue = node.url; - const newValue = transformFunctions.url(node.url, siteUrl, itemPath, options); + const newValue = transformFunctions.url(oldValue, siteUrl, itemPath, options); if (newValue !== oldValue) { replacements.push({ @@ -96,4 +113,4 @@ function markdownTransform(markdown = '', siteUrl, transformFunctions, itemPath, return result; } -module.exports = markdownTransform; +export default markdownTransform; diff --git a/packages/url-utils/src/utils/mobiledoc-absolute-to-relative.ts b/packages/url-utils/src/utils/mobiledoc-absolute-to-relative.ts index c6736d3f2..05c330338 100644 --- a/packages/url-utils/src/utils/mobiledoc-absolute-to-relative.ts +++ b/packages/url-utils/src/utils/mobiledoc-absolute-to-relative.ts @@ -1,17 +1,22 @@ -// @ts-nocheck -const absoluteToRelative = require('./absolute-to-relative'); -const mobiledocTransform = require('./mobiledoc-transform'); +import type {MobiledocTransformOptionsInput} from './types'; +import type {AbsoluteToRelativeOptionsInput} from './absolute-to-relative'; +import absoluteToRelative from './absolute-to-relative'; +import mobiledocTransform from './mobiledoc-transform'; -function mobiledocAbsoluteToRelative(serializedMobiledoc, siteUrl, _options = {}) { - const defaultOptions = {assetsOnly: false, secure: false, cardTransformers: []}; - const overrideOptions = {siteUrl, transformType: 'absoluteToRelative'}; +function mobiledocAbsoluteToRelative( + serializedMobiledoc: string, + siteUrl: string, + _options: MobiledocTransformOptionsInput = {} +): string { + const defaultOptions: MobiledocTransformOptionsInput = {assetsOnly: false, secure: false, cardTransformers: []}; + const overrideOptions: MobiledocTransformOptionsInput = {siteUrl, transformType: 'absoluteToRelative'}; const options = Object.assign({}, defaultOptions, _options, overrideOptions); - const transformFunction = function (_url, _siteUrl, _itemPath, __options) { + const transformFunction = function (_url: string, _siteUrl: string, _itemPath: string | null, __options: AbsoluteToRelativeOptionsInput): string { return absoluteToRelative(_url, _siteUrl, __options); }; return mobiledocTransform(serializedMobiledoc, siteUrl, transformFunction, '', options); } -module.exports = mobiledocAbsoluteToRelative; +export default mobiledocAbsoluteToRelative; diff --git a/packages/url-utils/src/utils/mobiledoc-absolute-to-transform-ready.ts b/packages/url-utils/src/utils/mobiledoc-absolute-to-transform-ready.ts index fc3d96912..6d5949b45 100644 --- a/packages/url-utils/src/utils/mobiledoc-absolute-to-transform-ready.ts +++ b/packages/url-utils/src/utils/mobiledoc-absolute-to-transform-ready.ts @@ -1,17 +1,21 @@ -// @ts-nocheck -const absoluteToTransformReady = require('./absolute-to-transform-ready'); -const mobiledocTransform = require('./mobiledoc-transform'); +import type {MobiledocTransformOptionsInput, AbsoluteToTransformReadyOptionsInput} from './types'; +import absoluteToTransformReady from './absolute-to-transform-ready'; +import mobiledocTransform from './mobiledoc-transform'; -function mobiledocAbsoluteToRelative(serializedMobiledoc, siteUrl, _options = {}) { - const defaultOptions = {assetsOnly: false, secure: false, cardTransformers: []}; - const overrideOptions = {siteUrl, transformType: 'toTransformReady'}; +function mobiledocAbsoluteToTransformReady( + serializedMobiledoc: string, + siteUrl: string, + _options: MobiledocTransformOptionsInput = {} +): string { + const defaultOptions: MobiledocTransformOptionsInput = {assetsOnly: false, secure: false, cardTransformers: []}; + const overrideOptions: MobiledocTransformOptionsInput = {siteUrl, transformType: 'toTransformReady'}; const options = Object.assign({}, defaultOptions, _options, overrideOptions); - const transformFunction = function (_url, _siteUrl, _itemPath, __options) { + const transformFunction = function (_url: string, _siteUrl: string, _itemPath: string | null, __options: AbsoluteToTransformReadyOptionsInput): string { return absoluteToTransformReady(_url, _siteUrl, __options); }; return mobiledocTransform(serializedMobiledoc, siteUrl, transformFunction, '', options); } -module.exports = mobiledocAbsoluteToRelative; +export default mobiledocAbsoluteToTransformReady; diff --git a/packages/url-utils/src/utils/mobiledoc-relative-to-absolute.ts b/packages/url-utils/src/utils/mobiledoc-relative-to-absolute.ts index 6bd3ab9c8..85c0f6538 100644 --- a/packages/url-utils/src/utils/mobiledoc-relative-to-absolute.ts +++ b/packages/url-utils/src/utils/mobiledoc-relative-to-absolute.ts @@ -1,13 +1,18 @@ -// @ts-nocheck -const relativeToAbsolute = require('./relative-to-absolute'); -const mobiledocTransform = require('./mobiledoc-transform'); +import type {MobiledocTransformOptionsInput} from './types'; +import relativeToAbsolute from './relative-to-absolute'; +import mobiledocTransform from './mobiledoc-transform'; -function mobiledocRelativeToAbsolute(serializedMobiledoc, siteUrl, itemPath, _options = {}) { - const defaultOptions = {assetsOnly: false, secure: false, cardTransformers: []}; - const overrideOptions = {siteUrl, itemPath, transformType: 'relativeToAbsolute'}; +function mobiledocRelativeToAbsolute( + serializedMobiledoc: string, + siteUrl: string, + itemPath: string | null, + _options: MobiledocTransformOptionsInput = {} +): string { + const defaultOptions: MobiledocTransformOptionsInput = {assetsOnly: false, secure: false, cardTransformers: []}; + const overrideOptions: MobiledocTransformOptionsInput = {siteUrl, itemPath, transformType: 'relativeToAbsolute'}; const options = Object.assign({}, defaultOptions, _options, overrideOptions); return mobiledocTransform(serializedMobiledoc, siteUrl, relativeToAbsolute, itemPath, options); } -module.exports = mobiledocRelativeToAbsolute; +export default mobiledocRelativeToAbsolute; diff --git a/packages/url-utils/src/utils/mobiledoc-relative-to-transform-ready.ts b/packages/url-utils/src/utils/mobiledoc-relative-to-transform-ready.ts index bd2ad1634..d7bdf5aa0 100644 --- a/packages/url-utils/src/utils/mobiledoc-relative-to-transform-ready.ts +++ b/packages/url-utils/src/utils/mobiledoc-relative-to-transform-ready.ts @@ -1,13 +1,18 @@ -// @ts-nocheck -const relativeToTransformReady = require('./relative-to-transform-ready'); -const mobiledocTransform = require('./mobiledoc-transform'); +import type {MobiledocTransformOptionsInput} from './types'; +import relativeToTransformReady from './relative-to-transform-ready'; +import mobiledocTransform from './mobiledoc-transform'; -function mobiledocRelativeToTransformReady(serializedMobiledoc, siteUrl, itemPath, _options = {}) { - const defaultOptions = {assetsOnly: false, secure: false, cardTransformers: []}; - const overrideOptions = {siteUrl, transformType: 'toTransformReady'}; +function mobiledocRelativeToTransformReady( + serializedMobiledoc: string, + siteUrl: string, + itemPath: string | null, + _options: MobiledocTransformOptionsInput = {} +): string { + const defaultOptions: MobiledocTransformOptionsInput = {assetsOnly: false, secure: false, cardTransformers: []}; + const overrideOptions: MobiledocTransformOptionsInput = {siteUrl, transformType: 'toTransformReady'}; const options = Object.assign({}, defaultOptions, _options, overrideOptions); return mobiledocTransform(serializedMobiledoc, siteUrl, relativeToTransformReady, itemPath, options); } -module.exports = mobiledocRelativeToTransformReady; +export default mobiledocRelativeToTransformReady; diff --git a/packages/url-utils/src/utils/mobiledoc-to-transform-ready.ts b/packages/url-utils/src/utils/mobiledoc-to-transform-ready.ts index 1e7c18543..3844f3223 100644 --- a/packages/url-utils/src/utils/mobiledoc-to-transform-ready.ts +++ b/packages/url-utils/src/utils/mobiledoc-to-transform-ready.ts @@ -1,14 +1,25 @@ -// @ts-nocheck -const mobiledocRelativeToAbsolute = require('./mobiledoc-relative-to-absolute'); -const mobiledocAbsoluteToTransformReady = require('./mobiledoc-absolute-to-transform-ready'); - -function mobiledocToTransformReady(mobiledoc, siteUrl, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; +import type {MobiledocTransformOptionsInput} from './types'; +import mobiledocRelativeToAbsolute from './mobiledoc-relative-to-absolute'; +import mobiledocAbsoluteToTransformReady from './mobiledoc-absolute-to-transform-ready'; + +function mobiledocToTransformReady( + mobiledoc: string, + siteUrl: string, + itemPath: string | null | MobiledocTransformOptionsInput, + options?: MobiledocTransformOptionsInput +): string { + let finalItemPath: string | null = null; + let finalOptions: MobiledocTransformOptionsInput = options || {}; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } - const absolute = mobiledocRelativeToAbsolute(mobiledoc, siteUrl, itemPath, options); - return mobiledocAbsoluteToTransformReady(absolute, siteUrl, options); + + const absolute = mobiledocRelativeToAbsolute(mobiledoc, siteUrl, finalItemPath, finalOptions); + return mobiledocAbsoluteToTransformReady(absolute, siteUrl, finalOptions); } -module.exports = mobiledocToTransformReady; +export default mobiledocToTransformReady; diff --git a/packages/url-utils/src/utils/mobiledoc-transform.ts b/packages/url-utils/src/utils/mobiledoc-transform.ts index 16128a8ea..ad1e46c25 100644 --- a/packages/url-utils/src/utils/mobiledoc-transform.ts +++ b/packages/url-utils/src/utils/mobiledoc-transform.ts @@ -1,35 +1,60 @@ -// @ts-nocheck -function mobiledocTransform(serializedMobiledoc, siteUrl, transformFunction, itemPath, _options = {}) { - const defaultOptions = {assetsOnly: false, secure: false, cardTransformers: []}; - const options = Object.assign({}, defaultOptions, _options, {siteUrl, itemPath}); +import type {MobiledocTransformOptions, MobiledocTransformOptionsInput, MobiledocCardTransformer, UrlTransformFunction} from './types'; + +interface MobiledocMarkup { + 0: string; + 1?: string[]; + [key: number]: unknown; +} + +interface MobiledocCard { + 0: string; + 1: unknown; + [key: number]: unknown; +} + +interface MobiledocDocument { + markups?: MobiledocMarkup[]; + cards?: MobiledocCard[]; + [key: string]: unknown; +} + +function mobiledocTransform( + serializedMobiledoc: string, + siteUrl: string, + transformFunction: UrlTransformFunction, + itemPath: string | null, + _options: MobiledocTransformOptionsInput = {} +): string { + const defaultOptions: MobiledocTransformOptionsInput = {assetsOnly: false, secure: false, cardTransformers: []}; + const options: MobiledocTransformOptions = Object.assign({}, defaultOptions, _options, {siteUrl, itemPath}) as MobiledocTransformOptions; // options.cardTransformers has an object for each card that has a name and multiple // transformer functions. By collecting the functions we need into a named object it // reduces the need to loop through and find the transformer for each card later on - const cardTransformers = {}; - options.cardTransformers.forEach((cardTransformer) => { + const cardTransformers: Record unknown) | undefined> = {}; + options.cardTransformers.forEach((cardTransformer: MobiledocCardTransformer) => { cardTransformers[cardTransformer.name] = cardTransformer[options.transformType]; }); - delete options.cardTransformers; + delete (options as Partial).cardTransformers; // function only accepts serialized mobiledoc so there's no chance of accidentally // modifying pass-by-reference objects - const mobiledoc = JSON.parse(serializedMobiledoc); + const mobiledoc: MobiledocDocument = JSON.parse(serializedMobiledoc); // any mobiledoc links will have an 'a' markup with an 'href' attribute - (mobiledoc.markups || []).forEach((markup) => { + (mobiledoc.markups || []).forEach((markup: MobiledocMarkup) => { if (markup[0] === 'a' && markup[1]) { // mobiledoc markup attrs are in an array like ['key', 'value', 'key2', 'value2'] // we only care about the href attr so loop through and find it so we can get the idx of it's value let hrefIndex = -1; - markup[1].forEach((attr, index) => { + markup[1].forEach((attr: string, index: number) => { if (attr === 'href') { hrefIndex = index + 1; } }); - if (hrefIndex !== -1) { + if (hrefIndex !== -1 && typeof markup[1][hrefIndex] === 'string') { const transformedUrl = transformFunction(markup[1][hrefIndex], siteUrl, itemPath, options); if (transformedUrl) { markup[1][hrefIndex] = transformedUrl; @@ -41,11 +66,12 @@ function mobiledocTransform(serializedMobiledoc, siteUrl, transformFunction, ite // any other urls will be within card payloads. We can't know what format // cards may contain so we sub out to card-specific transform functions that // are passed in as options from the consuming application. - (mobiledoc.cards || []).forEach((card) => { - const [name, payload] = card; + (mobiledoc.cards || []).forEach((card: MobiledocCard) => { + const name = card[0]; + const payload = card[1]; if (cardTransformers[name]) { // transformers take a payload and return a transformed payload - const transformedPayload = cardTransformers[name](payload, options); + const transformedPayload = cardTransformers[name](payload, options as MobiledocTransformOptions); card[1] = transformedPayload; } }); @@ -53,4 +79,4 @@ function mobiledocTransform(serializedMobiledoc, siteUrl, transformFunction, ite return JSON.stringify(mobiledoc); } -module.exports = mobiledocTransform; +export default mobiledocTransform; diff --git a/packages/url-utils/src/utils/plaintext-absolute-to-transform-ready.ts b/packages/url-utils/src/utils/plaintext-absolute-to-transform-ready.ts index 79bbc29f5..39fec1d75 100644 --- a/packages/url-utils/src/utils/plaintext-absolute-to-transform-ready.ts +++ b/packages/url-utils/src/utils/plaintext-absolute-to-transform-ready.ts @@ -1,13 +1,18 @@ -// @ts-nocheck -const absoluteToTransformReady = require('./absolute-to-transform-ready'); -const {escapeRegExp} = require('./build-early-exit-match'); +import type {AbsoluteToTransformReadyOptionsInput, BaseUrlOptionsInput} from './types'; +import absoluteToTransformReady from './absolute-to-transform-ready'; +import buildEarlyExitMatchModule from './build-early-exit-match'; +const {escapeRegExp} = buildEarlyExitMatchModule; +import {URL} from 'url'; -function buildLinkRegex(rootUrl, options = {}) { +type PlaintextAbsoluteToTransformReadyOptions = AbsoluteToTransformReadyOptionsInput & BaseUrlOptionsInput; +type PlaintextAbsoluteToTransformReadyOptionsInput = Partial; + +function buildLinkRegex(rootUrl: string, options: PlaintextAbsoluteToTransformReadyOptionsInput = {}): RegExp | null { // Build a regex that matches links from ANY configured base URL (site + CDNs) const baseUrls = [rootUrl, options.imageBaseUrl, options.filesBaseUrl, options.mediaBaseUrl] - .filter(Boolean); + .filter((value): value is string => Boolean(value)); - const patterns = baseUrls.map((baseUrl) => { + const patterns = baseUrls.map((baseUrl: string) => { const parsed = new URL(baseUrl); const escapedUrl = escapeRegExp(`${parsed.hostname}${parsed.pathname.replace(/\/$/, '')}`); return escapedUrl; @@ -21,21 +26,27 @@ function buildLinkRegex(rootUrl, options = {}) { return new RegExp(` \\[(https?://${pattern}.*?)\\]`, 'g'); } -const plaintextAbsoluteToTransformReady = function plaintextAbsoluteToTransformReady(plaintext, rootUrl, itemPath, options) { +const plaintextAbsoluteToTransformReady = function plaintextAbsoluteToTransformReady( + plaintext: string, + rootUrl: string, + itemPath: string | null | PlaintextAbsoluteToTransformReadyOptionsInput, + options?: PlaintextAbsoluteToTransformReadyOptionsInput +): string { // itemPath is optional, if it's an object may be the options param instead - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + let finalOptions: PlaintextAbsoluteToTransformReadyOptionsInput = options || {}; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; } // plaintext links look like "Link title [url]" // those links are all we care about so we can do a fast regex here - const linkRegex = buildLinkRegex(rootUrl, options); + const linkRegex = buildLinkRegex(rootUrl, finalOptions); - return plaintext.replace(linkRegex, function (fullMatch, url) { - const newUrl = absoluteToTransformReady(`${url}`, rootUrl, options); + return plaintext.replace(linkRegex as RegExp, function (fullMatch: string, url: string): string { + const newUrl = absoluteToTransformReady(`${url}`, rootUrl, finalOptions); return ` [${newUrl}]`; }); }; -module.exports = plaintextAbsoluteToTransformReady; +export default plaintextAbsoluteToTransformReady; diff --git a/packages/url-utils/src/utils/plaintext-relative-to-transform-ready.ts b/packages/url-utils/src/utils/plaintext-relative-to-transform-ready.ts index ea117eeeb..de43009c5 100644 --- a/packages/url-utils/src/utils/plaintext-relative-to-transform-ready.ts +++ b/packages/url-utils/src/utils/plaintext-relative-to-transform-ready.ts @@ -1,19 +1,29 @@ -// @ts-nocheck -const relativeToTransformReady = require('./relative-to-transform-ready'); +import type {RelativeToTransformReadyOptionsInput} from './relative-to-transform-ready'; +import relativeToTransformReady from './relative-to-transform-ready'; -const plaintextRelativeToTransformReady = function plaintextRelativeToTransformReady(plaintext, rootUrl, itemPath, options) { +const plaintextRelativeToTransformReady = function plaintextRelativeToTransformReady( + plaintext: string, + rootUrl: string, + itemPath: string | null | RelativeToTransformReadyOptionsInput, + options?: RelativeToTransformReadyOptionsInput +): string { // itemPath is optional, if it's an object may be the options param instead - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + let finalItemPath: string | null = null; + let finalOptions: RelativeToTransformReadyOptionsInput = options || {}; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } // plaintext links look like "Link title [url]" // those are all we care about so we can do a fast regex here - return plaintext.replace(/ \[(\/.*?)\]/g, function (fullMatch, path) { - const newPath = relativeToTransformReady(`${path}`, rootUrl, itemPath, options); + return plaintext.replace(/ \[(\/.*?)\]/g, function (fullMatch: string, path: string): string { + const newPath = relativeToTransformReady(`${path}`, rootUrl, finalItemPath, finalOptions); return ` [${newPath}]`; }); }; -module.exports = plaintextRelativeToTransformReady; +export default plaintextRelativeToTransformReady; diff --git a/packages/url-utils/src/utils/plaintext-to-transform-ready.ts b/packages/url-utils/src/utils/plaintext-to-transform-ready.ts index f415c4315..53e7fd7de 100644 --- a/packages/url-utils/src/utils/plaintext-to-transform-ready.ts +++ b/packages/url-utils/src/utils/plaintext-to-transform-ready.ts @@ -1,14 +1,28 @@ -// @ts-nocheck -const plaintextRelativeToTransformReady = require('./plaintext-relative-to-transform-ready'); -const plaintextAbsoluteToTransformReady = require('./plaintext-absolute-to-transform-ready'); - -function plaintextToTransformReady(plaintext, siteUrl, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; +import type {UnknownRecord} from './types'; +import plaintextRelativeToTransformReady from './plaintext-relative-to-transform-ready'; +import plaintextAbsoluteToTransformReady from './plaintext-absolute-to-transform-ready'; + +type PlaintextTransformOptions = UnknownRecord; +type PlaintextTransformOptionsInput = Partial; + +function plaintextToTransformReady( + plaintext: string, + siteUrl: string, + itemPath: string | null | PlaintextTransformOptionsInput, + options?: PlaintextTransformOptionsInput +): string { + let finalItemPath: string | null = null; + let finalOptions: PlaintextTransformOptionsInput = options || {}; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } - const relativeTransformed = plaintextRelativeToTransformReady(plaintext, siteUrl, itemPath, options); - return plaintextAbsoluteToTransformReady(relativeTransformed, siteUrl, options); + + const relativeTransformed = plaintextRelativeToTransformReady(plaintext, siteUrl, finalItemPath, finalOptions); + return plaintextAbsoluteToTransformReady(relativeTransformed, siteUrl, finalOptions); } -module.exports = plaintextToTransformReady; +export default plaintextToTransformReady; diff --git a/packages/url-utils/src/utils/relative-to-absolute.ts b/packages/url-utils/src/utils/relative-to-absolute.ts index 63345e71d..893245501 100644 --- a/packages/url-utils/src/utils/relative-to-absolute.ts +++ b/packages/url-utils/src/utils/relative-to-absolute.ts @@ -1,7 +1,9 @@ -// @ts-nocheck -// require the whatwg compatible URL library (same behaviour in node and browser) -const {URL} = require('url'); -const urlJoin = require('./url-join'); +import type {SecureOptions, SecureOptionsInput} from './types'; +import {URL} from 'url'; +import urlJoin from './url-join'; + +export type RelativeToAbsoluteOptions = SecureOptions; +export type RelativeToAbsoluteOptionsInput = SecureOptionsInput; // NOTE: Ghost's relative->absolute handling is a little strange when the rootUrl // includes a subdirectory. Root-relative paths such as /content/image.jpg are @@ -22,28 +24,38 @@ const urlJoin = require('./url-join'); * @param {object} options * @returns {string} The passed in url or an absolute URL using */ -const relativeToAbsolute = function relativeToAbsolute(path, rootUrl, itemPath, _options) { +const relativeToAbsolute = function relativeToAbsolute( + path: string, + rootUrl: string, + itemPath: string | null | RelativeToAbsoluteOptionsInput, + _options?: RelativeToAbsoluteOptionsInput +): string { // itemPath is optional, if it's an object it may be the options param instead - if (typeof itemPath === 'object' && !_options) { - _options = itemPath; - itemPath = null; + let finalItemPath: string | null = null; + let finalOptions: RelativeToAbsoluteOptionsInput = _options || {}; + + if (typeof itemPath === 'object' && itemPath !== null && !_options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } // itemPath could be sent as a full url in which case, extract the pathname - if (itemPath && itemPath.match(/^http/)) { - const itemUrl = new URL(itemPath); - itemPath = itemUrl.pathname; + if (finalItemPath && finalItemPath.match(/^http/)) { + const itemUrl = new URL(finalItemPath); + finalItemPath = itemUrl.pathname; } - const defaultOptions = { + const defaultOptions: RelativeToAbsoluteOptionsInput = { assetsOnly: false, staticImageUrlPrefix: 'content/images' }; - const options = Object.assign({}, defaultOptions, _options); + const options = Object.assign({}, defaultOptions, finalOptions); // return the path as-is if it's not an asset path and we're only modifying assets if (options.assetsOnly) { - const staticImageUrlPrefixRegex = new RegExp(options.staticImageUrlPrefix); + const staticImageUrlPrefixRegex = new RegExp(options.staticImageUrlPrefix as string); if (!path.match(staticImageUrlPrefixRegex)) { return path; } @@ -51,7 +63,7 @@ const relativeToAbsolute = function relativeToAbsolute(path, rootUrl, itemPath, // if URL is absolute return it as-is try { - const parsed = new URL(path, 'http://relative'); + const parsed: URL = new URL(path, 'http://relative'); if (parsed.origin !== 'http://relative') { return path; @@ -71,7 +83,7 @@ const relativeToAbsolute = function relativeToAbsolute(path, rootUrl, itemPath, } // return the path as-is if it's not root-relative and we have no itemPath - if (!itemPath && !path.match(/^\//)) { + if (!finalItemPath && !path.match(/^\//)) { return path; } @@ -80,8 +92,8 @@ const relativeToAbsolute = function relativeToAbsolute(path, rootUrl, itemPath, rootUrl = `${rootUrl}/`; } - const parsedRootUrl = new URL(rootUrl); - const basePath = path.startsWith('/') ? '' : itemPath; + const parsedRootUrl: URL = new URL(rootUrl); + const basePath = path.startsWith('/') ? '' : (finalItemPath || ''); const fullPath = urlJoin([parsedRootUrl.pathname, basePath, path], {rootUrl}); const absoluteUrl = new URL(fullPath, rootUrl); @@ -92,4 +104,4 @@ const relativeToAbsolute = function relativeToAbsolute(path, rootUrl, itemPath, return absoluteUrl.toString(); }; -module.exports = relativeToAbsolute; +export default relativeToAbsolute; diff --git a/packages/url-utils/src/utils/relative-to-transform-ready.ts b/packages/url-utils/src/utils/relative-to-transform-ready.ts index 3268d11f3..b1010afac 100644 --- a/packages/url-utils/src/utils/relative-to-transform-ready.ts +++ b/packages/url-utils/src/utils/relative-to-transform-ready.ts @@ -1,37 +1,61 @@ -// @ts-nocheck -const relativeToAbsolute = require('./relative-to-absolute'); +import type { + TransformReadyReplacementOptions +} from './types'; +import relativeToAbsolute from './relative-to-absolute'; +import {URL} from 'url'; -const relativeToTransformReady = function (url, root, itemPath, _options) { +export interface RelativeToTransformReadyOptions extends TransformReadyReplacementOptions { + staticImageUrlPrefix: string; + secure: boolean; +} + +export type RelativeToTransformReadyOptionsInput = Partial; + +const relativeToTransformReady = function ( + url: string, + root: string, + itemPath: string | null | RelativeToTransformReadyOptionsInput, + _options?: RelativeToTransformReadyOptionsInput +): string { // itemPath is optional, if it's an object may be the options param instead - if (typeof itemPath === 'object' && !_options) { - _options = itemPath; - itemPath = null; + let finalItemPath: string | null = null; + let finalOptions: RelativeToTransformReadyOptionsInput = _options || {}; + + if (typeof itemPath === 'object' && itemPath !== null && !_options) { + finalOptions = itemPath; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } - const defaultOptions = { + const defaultOptions: RelativeToTransformReadyOptionsInput = { replacementStr: '__GHOST_URL__', staticImageUrlPrefix: 'content/images' }; - const overrideOptions = { + const overrideOptions: RelativeToTransformReadyOptionsInput = { secure: false }; - const options = Object.assign({}, defaultOptions, _options, overrideOptions); + const options = Object.assign({}, defaultOptions, finalOptions, overrideOptions); // convert to absolute - const absoluteUrl = relativeToAbsolute(url, root, itemPath, options); + const absoluteUrl = relativeToAbsolute(url, root, finalItemPath, options); if (absoluteUrl === url) { return url; } - const rootUrl = new URL(root); + const rootUrl: URL = new URL(root); const rootPathname = rootUrl.pathname.replace(/\/$/, ''); // only convert to transform-ready if root url has no subdirectory or the subdirectory matches if (!url.match(/^\//) || rootPathname === '' || url.indexOf(rootPathname) === 0 || url.indexOf(`/${options.staticImageUrlPrefix}`) === 0) { + // normalize root to match the protocol of absoluteUrl (in case secure option changed it) + const absoluteUrlParsed = new URL(absoluteUrl); + const normalizedRoot = `${absoluteUrlParsed.protocol}//${rootUrl.host}${rootUrl.pathname}`.replace(/\/$/, ''); + // replace root with replacement string const transformedUrl = absoluteUrl - .replace(root, `${options.replacementStr}/`) // always have trailing slash after magic string + .replace(normalizedRoot, `${options.replacementStr}/`) // always have trailing slash after magic string .replace(/([^:])\/\//g, '$1/'); return transformedUrl; @@ -40,4 +64,4 @@ const relativeToTransformReady = function (url, root, itemPath, _options) { return url; }; -module.exports = relativeToTransformReady; +export default relativeToTransformReady; diff --git a/packages/url-utils/src/utils/replace-permalink.ts b/packages/url-utils/src/utils/replace-permalink.ts index 532bfbbcc..b8fbe6389 100644 --- a/packages/url-utils/src/utils/replace-permalink.ts +++ b/packages/url-utils/src/utils/replace-permalink.ts @@ -1,14 +1,24 @@ -// @ts-nocheck -const moment = require('moment-timezone'); +import * as moment from 'moment-timezone'; + +interface PermalinkResource { + published_at?: string | number | Date | null; + primary_author?: { + slug: string; + } | null; + primary_tag?: { + slug: string; + } | null; + slug: string; + id: string; +} /** * creates the url path for a post based on blog timezone and permalink pattern */ -function replacePermalink(permalink, resource, timezone = 'UTC') { - const output = permalink; +function replacePermalink(permalink: string, resource: PermalinkResource, timezone: string = 'UTC'): string { const primaryTagFallback = 'all'; const publishedAtMoment = moment.tz(resource.published_at || Date.now(), timezone); - const permalinkLookUp = { + const permalinkLookUp: Record string> = { year: function () { return publishedAtMoment.format('YYYY'); }, @@ -19,7 +29,7 @@ function replacePermalink(permalink, resource, timezone = 'UTC') { return publishedAtMoment.format('DD'); }, author: function () { - return resource.primary_author.slug; + return resource.primary_author?.slug ?? 'undefined'; }, primary_author: function () { return resource.primary_author ? resource.primary_author.slug : primaryTagFallback; @@ -37,11 +47,15 @@ function replacePermalink(permalink, resource, timezone = 'UTC') { // replace tags like :slug or :year with actual values const permalinkKeys = Object.keys(permalinkLookUp); - return output.replace(/(:[a-z_]+)/g, function (match) { - if (permalinkKeys.includes(match.substr(1))) { - return permalinkLookUp[match.substr(1)](); + return permalink.replace(/(:[a-z_]+)/g, function (match: string): string { + const key = match.slice(1); + if (permalinkKeys.includes(key)) { + // Known route segment - use the lookup function + return permalinkLookUp[key](); } + // Unknown route segment - return 'undefined' string + return 'undefined'; }); } -module.exports = replacePermalink; +export default replacePermalink; diff --git a/packages/url-utils/src/utils/strip-subdirectory-from-path.ts b/packages/url-utils/src/utils/strip-subdirectory-from-path.ts index d006b2426..b0e05931e 100644 --- a/packages/url-utils/src/utils/strip-subdirectory-from-path.ts +++ b/packages/url-utils/src/utils/strip-subdirectory-from-path.ts @@ -1,5 +1,4 @@ -// @ts-nocheck -const {URL} = require('url'); +import {URL} from 'url'; /** * Removes the directory in the root url from the relative path @@ -8,13 +7,13 @@ const {URL} = require('url'); * @param {string} rootUrl Root URL (eg, 'https://mysite.com/my/subdir/) * @returns {string} Path relative to the rootUrl's path */ -const stripSubdirectoryFromPath = function stripSubdirectoryFromPath(path = '', rootUrl = '') { +const stripSubdirectoryFromPath = function stripSubdirectoryFromPath(path: string = '', rootUrl: string = ''): string { // force root to always have a trailing-slash for consistent behaviour if (!rootUrl.endsWith('/')) { rootUrl = `${rootUrl}/`; } - let parsedRoot; + let parsedRoot: URL; try { parsedRoot = new URL(rootUrl); @@ -34,4 +33,4 @@ const stripSubdirectoryFromPath = function stripSubdirectoryFromPath(path = '', return path; }; -module.exports = stripSubdirectoryFromPath; +export default stripSubdirectoryFromPath; diff --git a/packages/url-utils/src/utils/to-transform-ready.ts b/packages/url-utils/src/utils/to-transform-ready.ts index 813a08220..2f836d6fb 100644 --- a/packages/url-utils/src/utils/to-transform-ready.ts +++ b/packages/url-utils/src/utils/to-transform-ready.ts @@ -1,14 +1,27 @@ -// @ts-nocheck -const relativeToAbsolute = require('./relative-to-absolute'); -const absoluteToTransformReady = require('./absolute-to-transform-ready'); +import type {AbsoluteToTransformReadyOptionsInput} from './absolute-to-transform-ready'; +import relativeToAbsolute, {type RelativeToAbsoluteOptionsInput} from './relative-to-absolute'; +import absoluteToTransformReady from './absolute-to-transform-ready'; -function toTransformReady(url, siteUrl, itemPath, options) { - if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; +export type ToTransformReadyOptions = RelativeToAbsoluteOptionsInput & AbsoluteToTransformReadyOptionsInput; + +function toTransformReady( + url: string, + siteUrl: string, + itemPath: string | null | ToTransformReadyOptions, + options?: ToTransformReadyOptions +): string { + let finalItemPath: string | null = null; + let finalOptions: ToTransformReadyOptions = options || {}; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + finalOptions = itemPath as ToTransformReadyOptions; + finalItemPath = null; + } else if (typeof itemPath === 'string') { + finalItemPath = itemPath; } - const absoluteUrl = relativeToAbsolute(url, siteUrl, itemPath, options); - return absoluteToTransformReady(absoluteUrl, siteUrl, options); + + const absoluteUrl = relativeToAbsolute(url, siteUrl, finalItemPath, finalOptions); + return absoluteToTransformReady(absoluteUrl, siteUrl, finalOptions); } -module.exports = toTransformReady; +export default toTransformReady; diff --git a/packages/url-utils/src/utils/transform-ready-to-absolute.ts b/packages/url-utils/src/utils/transform-ready-to-absolute.ts index 61d759eea..18ab8c486 100644 --- a/packages/url-utils/src/utils/transform-ready-to-absolute.ts +++ b/packages/url-utils/src/utils/transform-ready-to-absolute.ts @@ -1,10 +1,23 @@ -// @ts-nocheck -function escapeRegExp(string) { +import type {TransformReadyReplacementOptions, BaseUrlOptions} from './types'; + +function escapeRegExp(string: string): string { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } -const transformReadyToAbsolute = function (str = '', root, _options = {}) { - const defaultOptions = { +export interface TransformReadyToAbsoluteOptions extends TransformReadyReplacementOptions, BaseUrlOptions { + staticImageUrlPrefix: string; + staticFilesUrlPrefix: string; + staticMediaUrlPrefix: string; +} + +export type TransformReadyToAbsoluteOptionsInput = Partial; + +const transformReadyToAbsolute = function ( + str: string = '', + root: string, + _options: TransformReadyToAbsoluteOptionsInput = {} +): string { + const defaultOptions: TransformReadyToAbsoluteOptions = { replacementStr: '__GHOST_URL__', staticImageUrlPrefix: 'content/images', staticFilesUrlPrefix: 'content/files', @@ -21,7 +34,7 @@ const transformReadyToAbsolute = function (str = '', root, _options = {}) { const replacementRegex = new RegExp(escapeRegExp(options.replacementStr), 'g'); - return str.replace(replacementRegex, (match, offset) => { + return str.replace(replacementRegex, (match: string, offset: number): string => { const remainder = str.slice(offset + match.length); if (remainder.startsWith(`/${options.staticMediaUrlPrefix}`) && options.mediaBaseUrl) { @@ -40,4 +53,4 @@ const transformReadyToAbsolute = function (str = '', root, _options = {}) { }); }; -module.exports = transformReadyToAbsolute; +export default transformReadyToAbsolute; diff --git a/packages/url-utils/src/utils/transform-ready-to-relative.ts b/packages/url-utils/src/utils/transform-ready-to-relative.ts index 33a567150..7678d57da 100644 --- a/packages/url-utils/src/utils/transform-ready-to-relative.ts +++ b/packages/url-utils/src/utils/transform-ready-to-relative.ts @@ -1,13 +1,21 @@ -// @ts-nocheck -function escapeRegExp(string) { +import type {TransformReadyReplacementOptions, TransformReadyReplacementOptionsInput} from './types'; +import {URL} from 'url'; + +function escapeRegExp(string: string): string { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } -const transformReadyToRelative = function (str = '', root, _options = {}) { - const defaultOptions = { +const transformReadyToRelative = function ( + str: string = '', + root: string, + _options: TransformReadyReplacementOptionsInput = {} +): string { + const defaultOptions: TransformReadyReplacementOptions = { + replacementStr: '__GHOST_URL__' + }; - const options = Object.assign({}, defaultOptions, _options); + const options: TransformReadyReplacementOptions = Object.assign({}, defaultOptions, _options); if (!str || str.indexOf(options.replacementStr) === -1) { return str; @@ -22,4 +30,4 @@ const transformReadyToRelative = function (str = '', root, _options = {}) { return str.replace(replacementRegex, subdir); }; -module.exports = transformReadyToRelative; +export default transformReadyToRelative; diff --git a/packages/url-utils/src/utils/types.ts b/packages/url-utils/src/utils/types.ts new file mode 100644 index 000000000..f2d9af099 --- /dev/null +++ b/packages/url-utils/src/utils/types.ts @@ -0,0 +1,123 @@ +export type UnknownRecord = Record; + +export interface AssetAwareOptions extends UnknownRecord { + assetsOnly: boolean; + staticImageUrlPrefix?: string; +} + +export type AssetAwareOptionsInput = Partial; + +export interface SecureOptions extends AssetAwareOptions { + secure?: boolean; +} + +export type SecureOptionsInput = Partial; + +export interface TransformReadyReplacementOptions extends UnknownRecord { + replacementStr: string; + withoutSubdirectory?: boolean; +} + +export type TransformReadyReplacementOptionsInput = Partial; + +// Options for CDN base URLs +export interface BaseUrlOptions extends UnknownRecord { + imageBaseUrl?: string | null; + filesBaseUrl?: string | null; + mediaBaseUrl?: string | null; +} + +export type BaseUrlOptionsInput = Partial; + +export interface EarlyExitOptions extends UnknownRecord { + earlyExitMatchStr?: string; +} + +export type EarlyExitOptionsInput = Partial; + +// Options for absolute-to-transform-ready function +export interface AbsoluteToTransformReadyOptions extends TransformReadyReplacementOptions, BaseUrlOptions, AssetAwareOptions { + staticFilesUrlPrefix?: string; + staticMediaUrlPrefix?: string; +} + +export type AbsoluteToTransformReadyOptionsInput = Partial; + +// Main URL transform function signature +export type UrlTransformFunction = ( + url: string, + siteUrl: string, + itemPath: string | null, + options: UnknownRecord +) => string; + +// Transform type for Mobiledoc and Lexical +export type TransformType = 'relativeToAbsolute' | 'absoluteToRelative' | 'toTransformReady'; + +export interface HtmlTransformOptions extends SecureOptions { + earlyExitMatchStr?: string; +} + +export type HtmlTransformOptionsInput = SecureOptionsInput & {earlyExitMatchStr?: string}; + +export interface MarkdownTransformOptions extends AssetAwareOptions { + ignoreProtocol: boolean; + earlyExitMatchStr?: string; +} + +export type MarkdownTransformOptionsInput = AssetAwareOptionsInput & {ignoreProtocol?: boolean; earlyExitMatchStr?: string}; + +export interface MarkdownTransformFunctions { + html: UrlTransformFunction; + url: UrlTransformFunction; +} + +export type CardTransformer = (payload: unknown, options: UnknownRecord) => unknown; + +export interface MobiledocCardTransformer { + name: string; + relativeToAbsolute?: CardTransformer; + absoluteToRelative?: CardTransformer; + toTransformReady?: CardTransformer; +} + +export interface MobiledocTransformOptions extends SecureOptions { + cardTransformers: MobiledocCardTransformer[]; + siteUrl: string; + itemPath: string | null; + transformType: TransformType; +} + +export type MobiledocTransformOptionsInput = Partial> & { + cardTransformers?: MobiledocCardTransformer[]; + siteUrl?: string; + itemPath?: string | null; + transformType?: TransformType; +}; +export type LexicalTransformFunction = (value: string) => string; +export interface LexicalUrlTransformMap { + [key: string]: string | LexicalUrlTransformMap; +} + +export interface LexicalNodeConfig { + getType(): string; + urlTransformMap?: LexicalUrlTransformMap; +} + +export type LexicalTransformRegistry = Partial>>; + +export interface LexicalTransformOptions extends SecureOptions { + nodes: LexicalNodeConfig[]; + transformMap: LexicalTransformRegistry; + transformType: TransformType; + siteUrl: string; + itemPath: string | null; +} + +export type LexicalTransformOptionsInput = Partial> & { + nodes?: LexicalNodeConfig[]; + transformMap?: LexicalTransformRegistry; + siteUrl?: string; + itemPath?: string | null; + transformType?: TransformType; +}; diff --git a/packages/url-utils/src/utils/url-join.ts b/packages/url-utils/src/utils/url-join.ts index a72b5429f..c2203d4e8 100644 --- a/packages/url-utils/src/utils/url-join.ts +++ b/packages/url-utils/src/utils/url-join.ts @@ -1,5 +1,8 @@ -// @ts-nocheck -const deduplicateSubdirectory = require('./deduplicate-subdirectory'); +import deduplicateSubdirectory from './deduplicate-subdirectory'; + +interface UrlJoinOptions { + rootUrl: string; +} /** urlJoin * Returns a URL/path for internal use in Ghost. @@ -8,7 +11,7 @@ const deduplicateSubdirectory = require('./deduplicate-subdirectory'); * @param {string} options.rootUrl used for deduplicating any subdirectories * @return {string} URL concatinated URL/path of arguments. */ -function urlJoin(parts, options) { +function urlJoin(parts: string[], options: UrlJoinOptions = {rootUrl: ''}): string { let prefixDoubleSlash = false; // Remove empty item at the beginning @@ -32,7 +35,11 @@ function urlJoin(parts, options) { url = url.replace(/^\//, '//'); } + if (!options.rootUrl) { + return url; + } + return deduplicateSubdirectory(url, options.rootUrl); } -module.exports = urlJoin; +export default urlJoin; diff --git a/packages/url-utils/test/unit/url-utils.test.js b/packages/url-utils/test/unit/url-utils.test.js index 9067f5b75..49c0537d2 100644 --- a/packages/url-utils/test/unit/url-utils.test.js +++ b/packages/url-utils/test/unit/url-utils.test.js @@ -4,7 +4,7 @@ require('../utils'); const assert = require('assert/strict'); const sinon = require('sinon'); -const UrlUtils = require('../../lib/UrlUtils'); +const UrlUtils = require('../../lib/UrlUtils').default; const configUrlHelpers = require('@tryghost/config-url-helpers'); const constants = { diff --git a/packages/url-utils/test/unit/utils/absolute-to-relative.test.js b/packages/url-utils/test/unit/utils/absolute-to-relative.test.js index eec1861c4..bc93e81ac 100644 --- a/packages/url-utils/test/unit/utils/absolute-to-relative.test.js +++ b/packages/url-utils/test/unit/utils/absolute-to-relative.test.js @@ -2,7 +2,7 @@ // const testUtils = require('./utils'); require('../../utils'); -const absoluteToRelative = require('../../../lib/utils/absolute-to-relative'); +const absoluteToRelative = require('../../../lib/utils/absolute-to-relative').default; describe('utils: absoluteToRelative()', function () { it('ignores relative URLs', function () { diff --git a/packages/url-utils/test/unit/utils/absolute-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/absolute-to-transform-ready.test.js index a9438d9ba..94815f8c2 100644 --- a/packages/url-utils/test/unit/utils/absolute-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/absolute-to-transform-ready.test.js @@ -2,7 +2,7 @@ // const testUtils = require('./utils'); require('../../utils'); -const absoluteToTransformReady = require('../../../lib/utils/absolute-to-transform-ready'); +const absoluteToTransformReady = require('../../../lib/utils/absolute-to-transform-ready').default; describe('utils: absoluteToTransformReady()', function () { it('ignores relative URLs', function () { diff --git a/packages/url-utils/test/unit/utils/deduplicate-double-slashes.test.js b/packages/url-utils/test/unit/utils/deduplicate-double-slashes.test.js index 4f4226bc9..5025baed2 100644 --- a/packages/url-utils/test/unit/utils/deduplicate-double-slashes.test.js +++ b/packages/url-utils/test/unit/utils/deduplicate-double-slashes.test.js @@ -1,6 +1,6 @@ require('../../utils'); -const deduplicateDoubleSlashes = require('../../../lib/utils/deduplicate-double-slashes'); +const deduplicateDoubleSlashes = require('../../../lib/utils/deduplicate-double-slashes').default; describe('utils: deduplicateDoubleSlashes()', function () { it('should deduplicate double slashes in URL', function () { diff --git a/packages/url-utils/test/unit/utils/deduplicate-subdirectory.test.js b/packages/url-utils/test/unit/utils/deduplicate-subdirectory.test.js index 4eb62c3f7..fb52f72b8 100644 --- a/packages/url-utils/test/unit/utils/deduplicate-subdirectory.test.js +++ b/packages/url-utils/test/unit/utils/deduplicate-subdirectory.test.js @@ -2,7 +2,7 @@ // const testUtils = require('./utils'); require('../../utils'); -const deduplicateSubdirectory = require('../../../lib/utils/deduplicate-subdirectory'); +const deduplicateSubdirectory = require('../../../lib/utils/deduplicate-subdirectory').default; describe('utils: deduplicateSubdirectory()', function () { describe('with url', function () { diff --git a/packages/url-utils/test/unit/utils/html-absolute-to-relative.test.js b/packages/url-utils/test/unit/utils/html-absolute-to-relative.test.js index 4c3d28a3d..e2b7bd405 100644 --- a/packages/url-utils/test/unit/utils/html-absolute-to-relative.test.js +++ b/packages/url-utils/test/unit/utils/html-absolute-to-relative.test.js @@ -5,7 +5,7 @@ require('../../utils'); const sinon = require('sinon'); const cheerio = require('cheerio'); -const htmlAbsoluteToRelative = require('../../../lib/utils/html-absolute-to-relative'); +const htmlAbsoluteToRelative = require('../../../lib/utils/html-absolute-to-relative').default; describe('utils: htmlAbsoluteToRelative()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/html-absolute-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/html-absolute-to-transform-ready.test.js index adda39a3d..7672203f6 100644 --- a/packages/url-utils/test/unit/utils/html-absolute-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/html-absolute-to-transform-ready.test.js @@ -7,7 +7,7 @@ const sinon = require('sinon'); const cheerio = require('cheerio'); const htmlTransform = rewire('../../../lib/utils/html-transform'); -const htmlAbsoluteToTransformReady = require('../../../lib/utils/html-absolute-to-transform-ready'); +const htmlAbsoluteToTransformReady = require('../../../lib/utils/html-absolute-to-transform-ready').default; describe('utils: htmlAbsoluteToTransformReady()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/html-relative-to-absolute.test.js b/packages/url-utils/test/unit/utils/html-relative-to-absolute.test.js index 05e363151..9396bf57f 100644 --- a/packages/url-utils/test/unit/utils/html-relative-to-absolute.test.js +++ b/packages/url-utils/test/unit/utils/html-relative-to-absolute.test.js @@ -7,7 +7,7 @@ const rewire = require('rewire'); const cheerio = require('cheerio'); const htmlTransform = rewire('../../../lib/utils/html-transform'); -const htmlRelativeToAbsolute = require('../../../lib/utils/html-relative-to-absolute'); +const htmlRelativeToAbsolute = require('../../../lib/utils/html-relative-to-absolute').default; describe('utils: htmlRelativeToAbsolute()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/html-relative-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/html-relative-to-transform-ready.test.js index e184a5f1a..0f99adad0 100644 --- a/packages/url-utils/test/unit/utils/html-relative-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/html-relative-to-transform-ready.test.js @@ -5,7 +5,7 @@ require('../../utils'); const sinon = require('sinon'); const cheerio = require('cheerio'); -const htmlRelativeToTransformReady = require('../../../lib/utils/html-relative-to-transform-ready'); +const htmlRelativeToTransformReady = require('../../../lib/utils/html-relative-to-transform-ready').default; describe('utils: htmlRelativeToTransformReady()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/html-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/html-to-transform-ready.test.js index 361b6f0b6..3f8ad88c5 100644 --- a/packages/url-utils/test/unit/utils/html-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/html-to-transform-ready.test.js @@ -1,6 +1,6 @@ require('../../utils'); -const htmlToTransformReady = require('../../../lib/utils/html-to-transform-ready'); +const htmlToTransformReady = require('../../../lib/utils/html-to-transform-ready').default; describe('utils: htmlToTransformReady()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/is-ssl.test.js b/packages/url-utils/test/unit/utils/is-ssl.test.js index eb11d2af0..43a6b31fd 100644 --- a/packages/url-utils/test/unit/utils/is-ssl.test.js +++ b/packages/url-utils/test/unit/utils/is-ssl.test.js @@ -1,4 +1,4 @@ -const isSSL = require('../../../lib/utils/is-ssl'); +const isSSL = require('../../../lib/utils/is-ssl').default; describe('isSSL', function () { it('detects https protocol correctly', function () { diff --git a/packages/url-utils/test/unit/utils/lexical-absolute-to-relative.test.js b/packages/url-utils/test/unit/utils/lexical-absolute-to-relative.test.js index fe551bcc8..ccf98e69b 100644 --- a/packages/url-utils/test/unit/utils/lexical-absolute-to-relative.test.js +++ b/packages/url-utils/test/unit/utils/lexical-absolute-to-relative.test.js @@ -2,8 +2,8 @@ // const testUtils = require('./utils'); require('../../utils'); -const UrlUtils = require('../../../lib/UrlUtils'); -const lexicalAbsoluteToRelative = require('../../../lib/utils/lexical-absolute-to-relative'); +const UrlUtils = require('../../../lib/UrlUtils').default; +const lexicalAbsoluteToRelative = require('../../../lib/utils/lexical-absolute-to-relative').default; describe('utils: lexicalAbsoluteToRelative()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/lexical-absolute-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/lexical-absolute-to-transform-ready.test.js index 10a37b285..e7f10d6f7 100644 --- a/packages/url-utils/test/unit/utils/lexical-absolute-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/lexical-absolute-to-transform-ready.test.js @@ -2,8 +2,8 @@ // const testUtils = require('./utils'); require('../../utils'); -const UrlUtils = require('../../../lib/UrlUtils'); -const lexicalAbsoluteToTransformReady = require('../../../lib/utils/lexical-absolute-to-transform-ready'); +const UrlUtils = require('../../../lib/UrlUtils').default; +const lexicalAbsoluteToTransformReady = require('../../../lib/utils/lexical-absolute-to-transform-ready').default; describe('utils: lexicalAbsoluteToTransformReady()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/lexical-relative-to-absolute.test.js b/packages/url-utils/test/unit/utils/lexical-relative-to-absolute.test.js index 0f4678dee..0df07e317 100644 --- a/packages/url-utils/test/unit/utils/lexical-relative-to-absolute.test.js +++ b/packages/url-utils/test/unit/utils/lexical-relative-to-absolute.test.js @@ -2,8 +2,8 @@ // const testUtils = require('./utils'); require('../../utils'); -const UrlUtils = require('../../../lib/UrlUtils'); -const lexicalRelativeToAbsolute = require('../../../lib/utils/lexical-relative-to-absolute'); +const UrlUtils = require('../../../lib/UrlUtils').default; +const lexicalRelativeToAbsolute = require('../../../lib/utils/lexical-relative-to-absolute').default; describe('utils: lexicalRelativeToAbsolute()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/lexical-relative-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/lexical-relative-to-transform-ready.test.js index ffed06fd1..75db4b7a9 100644 --- a/packages/url-utils/test/unit/utils/lexical-relative-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/lexical-relative-to-transform-ready.test.js @@ -2,8 +2,8 @@ // const testUtils = require('./utils'); require('../../utils'); -const UrlUtils = require('../../../lib/UrlUtils'); -const lexicalRelativeToTransformReady = require('../../../lib/utils/lexical-relative-to-transform-ready'); +const UrlUtils = require('../../../lib/UrlUtils').default; +const lexicalRelativeToTransformReady = require('../../../lib/utils/lexical-relative-to-transform-ready').default; describe('utils: lexicalRelativeToTransformReady()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/lexical-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/lexical-to-transform-ready.test.js index fa3c2de8d..6808cac81 100644 --- a/packages/url-utils/test/unit/utils/lexical-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/lexical-to-transform-ready.test.js @@ -1,6 +1,6 @@ require('../../utils'); -const lexicalToTransformReady = require('../../../lib/utils/lexical-to-transform-ready'); +const lexicalToTransformReady = require('../../../lib/utils/lexical-to-transform-ready').default; describe('utils: lexicalToTransformReady()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/markdown-absolute-to-relative.test.js b/packages/url-utils/test/unit/utils/markdown-absolute-to-relative.test.js index 601077e34..bed51739c 100644 --- a/packages/url-utils/test/unit/utils/markdown-absolute-to-relative.test.js +++ b/packages/url-utils/test/unit/utils/markdown-absolute-to-relative.test.js @@ -8,8 +8,9 @@ const rewire = require('rewire'); const sinon = require('sinon'); const remark = require('remark'); -const markdownTransform = rewire('../../../lib/utils/markdown-transform'); -const markdownAbsoluteToRelative = rewire('../../../lib/utils/markdown-absolute-to-relative'); +const markdownTransformRewired = rewire('../../../lib/utils/markdown-transform'); +const markdownAbsoluteToRelativeRewired = rewire('../../../lib/utils/markdown-absolute-to-relative'); +const markdownAbsoluteToRelative = markdownAbsoluteToRelativeRewired.default; describe('utils: markdownAbsoluteToRelative()', function () { const siteUrl = 'http://my-ghost-blog.com'; @@ -123,8 +124,8 @@ Testing Inline with **markdown** beforeEach(function () { sandbox = sinon.createSandbox(); remarkSpy = sinon.spy(remark); - markdownTransform.__set__('remark', remarkSpy); - markdownAbsoluteToRelative.__set__('markdownTransform', markdownTransform); + markdownTransformRewired.__set__('remark', remarkSpy); + markdownAbsoluteToRelativeRewired.__set__('markdown_transform_1', markdownTransformRewired); }); afterEach(function () { diff --git a/packages/url-utils/test/unit/utils/markdown-absolute-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/markdown-absolute-to-transform-ready.test.js index 96ddc627b..bedb6b37e 100644 --- a/packages/url-utils/test/unit/utils/markdown-absolute-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/markdown-absolute-to-transform-ready.test.js @@ -8,8 +8,9 @@ const rewire = require('rewire'); const sinon = require('sinon'); const remark = require('remark'); -const markdownTransform = rewire('../../../lib/utils/markdown-transform'); -const markdownAbsoluteToTransformReady = rewire('../../../lib/utils/markdown-absolute-to-transform-ready'); +const markdownTransformRewired = rewire('../../../lib/utils/markdown-transform'); +const markdownAbsoluteToTransformReadyRewired = rewire('../../../lib/utils/markdown-absolute-to-transform-ready'); +const markdownAbsoluteToTransformReady = markdownAbsoluteToTransformReadyRewired.default; describe('utils: markdownAbsoluteToTransformReady()', function () { const siteUrl = 'http://my-ghost-blog.com'; @@ -290,8 +291,8 @@ Testing with markdown beforeEach(function () { sandbox = sinon.createSandbox(); remarkSpy = sinon.spy(remark); - markdownTransform.__set__('remark', remarkSpy); - markdownAbsoluteToTransformReady.__set__('markdownTransform', markdownTransform); + markdownTransformRewired.__set__('remark', remarkSpy); + markdownAbsoluteToTransformReadyRewired.__set__('markdown_transform_1', markdownTransformRewired); }); afterEach(function () { diff --git a/packages/url-utils/test/unit/utils/markdown-relative-to-absolute.test.js b/packages/url-utils/test/unit/utils/markdown-relative-to-absolute.test.js index 39e250f22..914db209b 100644 --- a/packages/url-utils/test/unit/utils/markdown-relative-to-absolute.test.js +++ b/packages/url-utils/test/unit/utils/markdown-relative-to-absolute.test.js @@ -8,8 +8,9 @@ const sinon = require('sinon'); const rewire = require('rewire'); const remark = require('remark'); -const markdownTransform = rewire('../../../lib/utils/markdown-transform'); -const markdownRelativeToAbsolute = rewire('../../../lib/utils/markdown-relative-to-absolute'); +const markdownTransformRewired = rewire('../../../lib/utils/markdown-transform'); +const markdownRelativeToAbsoluteRewired = rewire('../../../lib/utils/markdown-relative-to-absolute'); +const markdownRelativeToAbsolute = markdownRelativeToAbsoluteRewired.default; describe('utils: markdownRelativeToAbsolute()', function () { const siteUrl = 'http://my-ghost-blog.com'; @@ -117,8 +118,8 @@ Testing Inline with **markdown** beforeEach(function () { sandbox = sinon.createSandbox(); remarkSpy = sinon.spy(remark); - markdownTransform.__set__('remark', remarkSpy); - markdownRelativeToAbsolute.__set__('markdownTransform', markdownTransform); + markdownTransformRewired.__set__('remark', remarkSpy); + markdownRelativeToAbsoluteRewired.__set__('markdown_transform_1', markdownTransformRewired); }); afterEach(function () { diff --git a/packages/url-utils/test/unit/utils/markdown-relative-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/markdown-relative-to-transform-ready.test.js index 76079cf59..49ddba1e6 100644 --- a/packages/url-utils/test/unit/utils/markdown-relative-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/markdown-relative-to-transform-ready.test.js @@ -8,8 +8,9 @@ const sinon = require('sinon'); const rewire = require('rewire'); const remark = require('remark'); -const markdownTransform = rewire('../../../lib/utils/markdown-transform'); -const markdownRelativeToTransformReady = rewire('../../../lib/utils/markdown-relative-to-transform-ready'); +const markdownTransformRewired = rewire('../../../lib/utils/markdown-transform'); +const markdownRelativeToTransformReadyRewired = rewire('../../../lib/utils/markdown-relative-to-transform-ready'); +const markdownRelativeToTransformReady = markdownRelativeToTransformReadyRewired.default; describe('utils: markdownRelativeToTransformReady()', function () { const siteUrl = 'http://my-ghost-blog.com'; @@ -171,8 +172,8 @@ Just testing beforeEach(function () { sandbox = sinon.createSandbox(); remarkSpy = sinon.spy(remark); - markdownTransform.__set__('remark', remarkSpy); - markdownRelativeToTransformReady.__set__('markdownTransform', markdownTransform); + markdownTransformRewired.__set__('remark', remarkSpy); + markdownRelativeToTransformReadyRewired.__set__('markdown_transform_1', markdownTransformRewired); }); afterEach(function () { diff --git a/packages/url-utils/test/unit/utils/markdown-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/markdown-to-transform-ready.test.js index 8e1524bfb..2aad57973 100644 --- a/packages/url-utils/test/unit/utils/markdown-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/markdown-to-transform-ready.test.js @@ -1,6 +1,6 @@ require('../../utils'); -const markdownToTransformReady = require('../../../lib/utils/markdown-to-transform-ready'); +const markdownToTransformReady = require('../../../lib/utils/markdown-to-transform-ready').default; describe('utils: markdownToTransformReady()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/mobiledoc-absolute-to-relative.test.js b/packages/url-utils/test/unit/utils/mobiledoc-absolute-to-relative.test.js index b0d60684c..fd1e713e2 100644 --- a/packages/url-utils/test/unit/utils/mobiledoc-absolute-to-relative.test.js +++ b/packages/url-utils/test/unit/utils/mobiledoc-absolute-to-relative.test.js @@ -4,7 +4,7 @@ require('../../utils'); const sinon = require('sinon'); -const mobiledocAbsoluteToRelative = require('../../../lib/utils/mobiledoc-absolute-to-relative'); +const mobiledocAbsoluteToRelative = require('../../../lib/utils/mobiledoc-absolute-to-relative').default; describe('utils: mobiledocAbsoluteToRelative()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/mobiledoc-absolute-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/mobiledoc-absolute-to-transform-ready.test.js index 5105f8f3f..5b42b0f94 100644 --- a/packages/url-utils/test/unit/utils/mobiledoc-absolute-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/mobiledoc-absolute-to-transform-ready.test.js @@ -4,7 +4,7 @@ require('../../utils'); const sinon = require('sinon'); -const mobiledocAbsoluteToTransformReady = require('../../../lib/utils/mobiledoc-absolute-to-transform-ready'); +const mobiledocAbsoluteToTransformReady = require('../../../lib/utils/mobiledoc-absolute-to-transform-ready').default; describe('utils: mobiledocAbsoluteToTransformReady()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/mobiledoc-relative-to-absolute.test.js b/packages/url-utils/test/unit/utils/mobiledoc-relative-to-absolute.test.js index 1de7842e9..19eef6e9b 100644 --- a/packages/url-utils/test/unit/utils/mobiledoc-relative-to-absolute.test.js +++ b/packages/url-utils/test/unit/utils/mobiledoc-relative-to-absolute.test.js @@ -4,7 +4,7 @@ require('../../utils'); const sinon = require('sinon'); -const mobiledocRelativeToAbsolute = require('../../../lib/utils/mobiledoc-relative-to-absolute'); +const mobiledocRelativeToAbsolute = require('../../../lib/utils/mobiledoc-relative-to-absolute').default; describe('utils: mobiledocRelativeToAbsolute()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/mobiledoc-relative-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/mobiledoc-relative-to-transform-ready.test.js index e6bf7cbb0..ca24afc5e 100644 --- a/packages/url-utils/test/unit/utils/mobiledoc-relative-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/mobiledoc-relative-to-transform-ready.test.js @@ -4,7 +4,7 @@ require('../../utils'); const sinon = require('sinon'); -const mobiledocRelativeToTransformReady = require('../../../lib/utils/mobiledoc-relative-to-transform-ready'); +const mobiledocRelativeToTransformReady = require('../../../lib/utils/mobiledoc-relative-to-transform-ready').default; describe('utils: mobiledocRelativeToTransformReady()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/mobiledoc-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/mobiledoc-to-transform-ready.test.js index 34b0c6174..640cbaa8b 100644 --- a/packages/url-utils/test/unit/utils/mobiledoc-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/mobiledoc-to-transform-ready.test.js @@ -1,6 +1,6 @@ require('../../utils'); -const mobiledocToTransformReady = require('../../../lib/utils/mobiledoc-to-transform-ready'); +const mobiledocToTransformReady = require('../../../lib/utils/mobiledoc-to-transform-ready').default; describe('utils: mobiledocToTransformReady()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/plaintext-absolute-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/plaintext-absolute-to-transform-ready.test.js index 89a0f286a..b20001678 100644 --- a/packages/url-utils/test/unit/utils/plaintext-absolute-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/plaintext-absolute-to-transform-ready.test.js @@ -2,7 +2,7 @@ // const testUtils = require('./utils'); require('../../utils'); -const plaintextAbsoluteToTransformReady = require('../../../lib/utils/plaintext-absolute-to-transform-ready'); +const plaintextAbsoluteToTransformReady = require('../../../lib/utils/plaintext-absolute-to-transform-ready').default; describe('utils: plaintextAbsoluteToTransformReady', function () { it('works', function () { diff --git a/packages/url-utils/test/unit/utils/plaintext-relative-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/plaintext-relative-to-transform-ready.test.js index dd182a95c..00f766b34 100644 --- a/packages/url-utils/test/unit/utils/plaintext-relative-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/plaintext-relative-to-transform-ready.test.js @@ -2,7 +2,7 @@ // const testUtils = require('./utils'); require('../../utils'); -const plaintextRelativeToTransformReady = require('../../../lib/utils/plaintext-relative-to-transform-ready'); +const plaintextRelativeToTransformReady = require('../../../lib/utils/plaintext-relative-to-transform-ready').default; describe('utils: plaintextRelativeToTransformReady', function () { it('works', function () { diff --git a/packages/url-utils/test/unit/utils/plaintext-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/plaintext-to-transform-ready.test.js index 8ae398be4..e302f2355 100644 --- a/packages/url-utils/test/unit/utils/plaintext-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/plaintext-to-transform-ready.test.js @@ -2,7 +2,7 @@ // const testUtils = require('./utils'); require('../../utils'); -const plaintextToTransformReady = require('../../../lib/utils/plaintext-to-transform-ready'); +const plaintextToTransformReady = require('../../../lib/utils/plaintext-to-transform-ready').default; describe('utils: plaintextToTransformReady', function () { it('works', function () { diff --git a/packages/url-utils/test/unit/utils/relative-to-absolute.test.js b/packages/url-utils/test/unit/utils/relative-to-absolute.test.js index 1c10d5092..08d8966dc 100644 --- a/packages/url-utils/test/unit/utils/relative-to-absolute.test.js +++ b/packages/url-utils/test/unit/utils/relative-to-absolute.test.js @@ -2,7 +2,7 @@ // const testUtils = require('./utils'); require('../../utils'); -const relativeToAbsolute = require('../../../lib/utils/relative-to-absolute'); +const relativeToAbsolute = require('../../../lib/utils/relative-to-absolute').default; describe('utils: relativeToAbsolute()', function () { it('ignores absolute URLs', function () { diff --git a/packages/url-utils/test/unit/utils/relative-to-transform-ready.test.js b/packages/url-utils/test/unit/utils/relative-to-transform-ready.test.js index 7d5cc30d5..4d2cb48bb 100644 --- a/packages/url-utils/test/unit/utils/relative-to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/relative-to-transform-ready.test.js @@ -2,7 +2,7 @@ // const testUtils = require('./utils'); require('../../utils'); -const relativeToTransformReady = require('../../../lib/utils/relative-to-transform-ready'); +const relativeToTransformReady = require('../../../lib/utils/relative-to-transform-ready').default; describe('utils: relativeToTransformReady()', function () { it('ignores absolute URLs', function () { diff --git a/packages/url-utils/test/unit/utils/replace-permalink.test.js b/packages/url-utils/test/unit/utils/replace-permalink.test.js index efcbc0b12..1293ab4c1 100644 --- a/packages/url-utils/test/unit/utils/replace-permalink.test.js +++ b/packages/url-utils/test/unit/utils/replace-permalink.test.js @@ -3,7 +3,7 @@ require('../../utils'); const moment = require('moment-timezone'); -const replacePermalink = require('../../../lib/utils/replace-permalink'); +const replacePermalink = require('../../../lib/utils/replace-permalink').default; describe('utils: replacePermalink()', function () { it('permalink is /:slug/, timezone is default', function () { diff --git a/packages/url-utils/test/unit/utils/strip-subdirectory-from-path.test.js b/packages/url-utils/test/unit/utils/strip-subdirectory-from-path.test.js index a26d1ceb1..264d9f012 100644 --- a/packages/url-utils/test/unit/utils/strip-subdirectory-from-path.test.js +++ b/packages/url-utils/test/unit/utils/strip-subdirectory-from-path.test.js @@ -2,7 +2,7 @@ // const testUtils = require('./utils'); require('../../utils'); -const stripSubdirectoryFromPath = require('../../../lib/utils/strip-subdirectory-from-path'); +const stripSubdirectoryFromPath = require('../../../lib/utils/strip-subdirectory-from-path').default; describe('utils: stripSubdomainFromPath()', function () { it('ignores rootUrl with no subdirectory', function () { diff --git a/packages/url-utils/test/unit/utils/to-transform-ready.test.js b/packages/url-utils/test/unit/utils/to-transform-ready.test.js index e7f76cd46..eaa2e4ce4 100644 --- a/packages/url-utils/test/unit/utils/to-transform-ready.test.js +++ b/packages/url-utils/test/unit/utils/to-transform-ready.test.js @@ -1,6 +1,6 @@ require('../../utils'); -const toTransformReady = require('../../../lib/utils/to-transform-ready'); +const toTransformReady = require('../../../lib/utils/to-transform-ready').default; describe('utils: toTransformReady()', function () { const siteUrl = 'http://my-ghost-blog.com'; diff --git a/packages/url-utils/test/unit/utils/transform-ready-to-absolute.test.js b/packages/url-utils/test/unit/utils/transform-ready-to-absolute.test.js index d773db8d6..9a962d47d 100644 --- a/packages/url-utils/test/unit/utils/transform-ready-to-absolute.test.js +++ b/packages/url-utils/test/unit/utils/transform-ready-to-absolute.test.js @@ -4,7 +4,7 @@ require('../../utils'); const fs = require('fs'); const path = require('path'); -const transformReadyToAbsolute = require('../../../lib/utils/transform-ready-to-absolute'); +const transformReadyToAbsolute = require('../../../lib/utils/transform-ready-to-absolute').default; describe('utils: transformReadyToAbsolute()', function () { describe('single url', function () { diff --git a/packages/url-utils/test/unit/utils/transform-ready-to-relative.test.js b/packages/url-utils/test/unit/utils/transform-ready-to-relative.test.js index d261b9ae6..2dc6ccc78 100644 --- a/packages/url-utils/test/unit/utils/transform-ready-to-relative.test.js +++ b/packages/url-utils/test/unit/utils/transform-ready-to-relative.test.js @@ -4,7 +4,7 @@ require('../../utils'); const fs = require('fs'); const path = require('path'); -const transformReadyToRelative = require('../../../lib/utils/transform-ready-to-relative'); +const transformReadyToRelative = require('../../../lib/utils/transform-ready-to-relative').default; describe('utils: transformReadyToRelative()', function () { describe('single url', function () { diff --git a/packages/url-utils/test/unit/utils/url-join.test.js b/packages/url-utils/test/unit/utils/url-join.test.js index af36673ba..b8c97b2a5 100644 --- a/packages/url-utils/test/unit/utils/url-join.test.js +++ b/packages/url-utils/test/unit/utils/url-join.test.js @@ -2,7 +2,7 @@ // const testUtils = require('./utils'); require('../../utils'); -const urlJoin = require('../../../lib/utils/url-join'); +const urlJoin = require('../../../lib/utils/url-join').default; describe('utils: urlJoin()', function () { it('should deduplicate slashes', function () {