From 3f65ce2bcbecfde8de4e8351fc412eb85c144c16 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Oct 2025 03:25:55 +0000 Subject: [PATCH 01/14] chore(url-utils): Add TypeScript configuration and dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add tsconfig.json with strict TypeScript configuration - Add TypeScript and type dependencies to package.json - Configure build scripts for TypeScript compilation - Update main entry point to dist/index.js - Add .gitignore for build artifacts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- packages/url-utils/.gitignore | 7 +++++++ packages/url-utils/package.json | 21 ++++++++++++++------- packages/url-utils/tsconfig.json | 28 ++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 packages/url-utils/.gitignore create mode 100644 packages/url-utils/tsconfig.json diff --git a/packages/url-utils/.gitignore b/packages/url-utils/.gitignore new file mode 100644 index 000000000..9776e61e0 --- /dev/null +++ b/packages/url-utils/.gitignore @@ -0,0 +1,7 @@ +node_modules/ +dist/ +*.log +.DS_Store +coverage/ +.nyc_output/ +.eslintcache diff --git a/packages/url-utils/package.json b/packages/url-utils/package.json index 17e004dc8..a9719b804 100644 --- a/packages/url-utils/package.json +++ b/packages/url-utils/package.json @@ -8,27 +8,34 @@ }, "author": "Ghost Foundation", "license": "MIT", - "main": "index.js", + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { - "dev": "echo \"Implement me!\"", - "test": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura --reporter html mocha './test/**/*.test.js'", - "lint": "eslint . --ext .js --cache", + "build": "tsc", + "dev": "tsc --watch", + "prepublishOnly": "yarn build", + "test": "yarn build && NODE_ENV=testing c8 --all --reporter text --reporter cobertura --reporter html mocha './test/**/*.test.js'", + "lint": "eslint . --ext .js,.ts --cache", "posttest": "yarn lint" }, "files": [ - "lib/", - "index.js" + "dist/", + "lib/" ], "publishConfig": { "access": "public" }, "devDependencies": { "@tryghost/config-url-helpers": "^1.0.17", + "@types/cheerio": "^0.22.35", + "@types/lodash": "^4.17.13", + "@types/node": "^22.10.2", "c8": "10.1.3", "mocha": "11.7.4", "rewire": "9.0.1", "should": "13.2.3", - "sinon": "21.0.0" + "sinon": "21.0.0", + "typescript": "^5.7.2" }, "dependencies": { "cheerio": "^0.22.0", diff --git a/packages/url-utils/tsconfig.json b/packages/url-utils/tsconfig.json new file mode 100644 index 000000000..60d630a1c --- /dev/null +++ b/packages/url-utils/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "declaration": true, + "outDir": "./dist", + "rootDir": "./", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "declarationMap": true, + "sourceMap": true + }, + "include": [ + "index.ts", + "lib/**/*.ts" + ], + "exclude": [ + "node_modules", + "dist", + "test" + ] +} From 792410da8b22a183cd64c779d84e9d52e160d9e6 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Oct 2025 03:26:31 +0000 Subject: [PATCH 02/14] chore(url-utils): Convert simple utility functions to TypeScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Convert is-ssl.js to TypeScript with proper return type - Convert deduplicate-double-slashes.js to TypeScript - Convert strip-subdirectory-from-path.js to TypeScript - Convert deduplicate-subdirectory.js to TypeScript These are the simplest utility functions with clear inputs and outputs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../lib/utils/deduplicate-double-slashes.ts | 5 +++ .../lib/utils/deduplicate-subdirectory.ts | 31 ++++++++++++++++ packages/url-utils/lib/utils/is-ssl.ts | 9 +++++ .../lib/utils/strip-subdirectory-from-path.ts | 36 +++++++++++++++++++ 4 files changed, 81 insertions(+) create mode 100644 packages/url-utils/lib/utils/deduplicate-double-slashes.ts create mode 100644 packages/url-utils/lib/utils/deduplicate-subdirectory.ts create mode 100644 packages/url-utils/lib/utils/is-ssl.ts create mode 100644 packages/url-utils/lib/utils/strip-subdirectory-from-path.ts diff --git a/packages/url-utils/lib/utils/deduplicate-double-slashes.ts b/packages/url-utils/lib/utils/deduplicate-double-slashes.ts new file mode 100644 index 000000000..c374d57d5 --- /dev/null +++ b/packages/url-utils/lib/utils/deduplicate-double-slashes.ts @@ -0,0 +1,5 @@ +function deduplicateDoubleSlashes(url: string): string { + return url.replace(/\/\//g, '/'); +} + +export = deduplicateDoubleSlashes; diff --git a/packages/url-utils/lib/utils/deduplicate-subdirectory.ts b/packages/url-utils/lib/utils/deduplicate-subdirectory.ts new file mode 100644 index 000000000..a749eefa1 --- /dev/null +++ b/packages/url-utils/lib/utils/deduplicate-subdirectory.ts @@ -0,0 +1,31 @@ +import {URL} from 'url'; + +/** + * Remove duplicated directories from the start of a path or url's path + * + * @param {string} url URL or pathname with possible duplicate subdirectory + * @param {string} rootUrl Root URL with an optional subdirectory + * @returns {string} URL or pathname with any duplicated subdirectory removed + */ +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}/`; + } + + const parsedRoot = new URL(rootUrl); + + // do nothing if rootUrl does not have a subdirectory + if (parsedRoot.pathname === '/') { + return url; + } + + const subdir = parsedRoot.pathname.replace(/(^\/|\/$)+/g, ''); + // we can have subdirs that match TLDs so we need to restrict matches to + // duplicates that start with a / or the beginning of the url + const subdirRegex = new RegExp(`(^|/)${subdir}/${subdir}(/|$)`); + + return url.replace(subdirRegex, `$1${subdir}/`); +}; + +export = deduplicateSubdirectory; diff --git a/packages/url-utils/lib/utils/is-ssl.ts b/packages/url-utils/lib/utils/is-ssl.ts new file mode 100644 index 000000000..b024cfe5f --- /dev/null +++ b/packages/url-utils/lib/utils/is-ssl.ts @@ -0,0 +1,9 @@ +// require the whatwg compatible URL library (same behaviour in node and browser) +import {URL} from 'url'; + +function isSSL(urlToParse: string): boolean { + const {protocol} = new URL(urlToParse); + return protocol === 'https:'; +} + +export = isSSL; diff --git a/packages/url-utils/lib/utils/strip-subdirectory-from-path.ts b/packages/url-utils/lib/utils/strip-subdirectory-from-path.ts new file mode 100644 index 000000000..3fdbdc68d --- /dev/null +++ b/packages/url-utils/lib/utils/strip-subdirectory-from-path.ts @@ -0,0 +1,36 @@ +import {URL} from 'url'; + +/** + * Removes the directory in the root url from the relative path + * + * @param {string} path Relative path (eg, '/my/subdir/my/file.png) + * @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 = ''): string { + // force root to always have a trailing-slash for consistent behaviour + if (!rootUrl.endsWith('/')) { + rootUrl = `${rootUrl}/`; + } + + let parsedRoot: URL; + + try { + parsedRoot = new URL(rootUrl); + } catch (e) { + return path; + } + + // do nothing if rootUrl does not have a subdirectory + if (parsedRoot.pathname === '/') { + return path; + } + + if (path.startsWith(parsedRoot.pathname)) { + return path.replace(parsedRoot.pathname, '/'); + } + + return path; +}; + +export = stripSubdirectoryFromPath; From 12cfccf7aa47c403bf0866f76a454b34427d0f47 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Oct 2025 03:27:38 +0000 Subject: [PATCH 03/14] chore(url-utils): Convert URL manipulation utilities to TypeScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Convert url-join.js to TypeScript with proper interface - Convert replace-permalink.js with Resource interface - Convert absolute-to-relative.js with options interface - Convert relative-to-absolute.js with options interface - Convert absolute-to-transform-ready.js with options interface Added proper type definitions for all function parameters and return types. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../lib/utils/absolute-to-relative.ts | 70 ++++++++++++ .../lib/utils/absolute-to-transform-ready.ts | 47 ++++++++ .../lib/utils/relative-to-absolute.ts | 100 ++++++++++++++++++ .../url-utils/lib/utils/replace-permalink.ts | 59 +++++++++++ packages/url-utils/lib/utils/url-join.ts | 41 +++++++ 5 files changed, 317 insertions(+) create mode 100644 packages/url-utils/lib/utils/absolute-to-relative.ts create mode 100644 packages/url-utils/lib/utils/absolute-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/relative-to-absolute.ts create mode 100644 packages/url-utils/lib/utils/replace-permalink.ts create mode 100644 packages/url-utils/lib/utils/url-join.ts diff --git a/packages/url-utils/lib/utils/absolute-to-relative.ts b/packages/url-utils/lib/utils/absolute-to-relative.ts new file mode 100644 index 000000000..ca170ef09 --- /dev/null +++ b/packages/url-utils/lib/utils/absolute-to-relative.ts @@ -0,0 +1,70 @@ +// require the whatwg compatible URL library (same behaviour in node and browser) +import {URL} from 'url'; +import stripSubdirectoryFromPath = require('./strip-subdirectory-from-path'); + +interface AbsoluteToRelativeOptions { + ignoreProtocol?: boolean; + withoutSubdirectory?: boolean; + assetsOnly?: boolean; + staticImageUrlPrefix?: string; +} + +/** + * Convert an absolute URL to a root-relative path if it matches the supplied root domain. + * + * @param {string} url Absolute URL to convert to relative if possible + * @param {string} rootUrl Absolute URL to which the returned relative URL will match the domain root + * @param {Object} [options] Options that affect the conversion + * @param {boolean} [options.ignoreProtocol=true] Ignore protocol when matching url to root + * @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: string, rootUrl: string, _options: AbsoluteToRelativeOptions = {}): string { + const defaultOptions: AbsoluteToRelativeOptions = { + ignoreProtocol: true, + withoutSubdirectory: false, + assetsOnly: false, + staticImageUrlPrefix: 'content/images' + }; + const options = Object.assign({}, defaultOptions, _options); + + if (options.assetsOnly) { + const staticImageUrlPrefixRegex = new RegExp(options.staticImageUrlPrefix!); + if (!url.match(staticImageUrlPrefixRegex)) { + return url; + } + } + + let parsedUrl: URL; + let parsedRoot: URL | undefined; + + try { + parsedUrl = new URL(url, 'http://relative'); + parsedRoot = parsedUrl.origin === 'null' ? undefined : new URL(rootUrl || parsedUrl.origin); + + // return the url as-is if it was relative or non-http + if (parsedUrl.origin === 'null' || parsedUrl.origin === 'http://relative') { + return url; + } + } catch (e) { + return url; + } + + const matchesHost = parsedUrl.host === parsedRoot!.host; + const matchesProtocol = parsedUrl.protocol === parsedRoot!.protocol; + const matchesPath = parsedUrl.pathname.indexOf(parsedRoot!.pathname) === 0; + + if (matchesHost && (options.ignoreProtocol || matchesProtocol) && matchesPath) { + let path = parsedUrl.href.replace(parsedUrl.origin, ''); + + if (options.withoutSubdirectory) { + path = stripSubdirectoryFromPath(path, rootUrl); + } + + return path; + } + + return url; +}; + +export = absoluteToRelative; diff --git a/packages/url-utils/lib/utils/absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/absolute-to-transform-ready.ts new file mode 100644 index 000000000..9d2ef83f5 --- /dev/null +++ b/packages/url-utils/lib/utils/absolute-to-transform-ready.ts @@ -0,0 +1,47 @@ +import {URL} from 'url'; +import absoluteToRelative = require('./absolute-to-relative'); + +interface AbsoluteToTransformReadyOptions { + replacementStr?: string; + withoutSubdirectory?: boolean; + assetsOnly?: boolean; + staticImageUrlPrefix?: string; +} + +const absoluteToTransformReady = function (url: string, root: string, _options?: AbsoluteToTransformReadyOptions): string { + const defaultOptions: AbsoluteToTransformReadyOptions = { + replacementStr: '__GHOST_URL__', + withoutSubdirectory: true + }; + const options = Object.assign({}, defaultOptions, _options); + + // return relative urls as-is + try { + const parsedURL = new URL(url, 'http://relative'); + if (parsedURL.origin === 'http://relative') { + return url; + } + } catch (e) { + // url was unparseable + return url; + } + + // convert to relative with stripped subdir + // always returns root-relative starting with forward slash + const relativeUrl = absoluteToRelative(url, root, options); + + // return still absolute urls as-is (eg. external site, mailto, etc) + try { + const parsedURL = new URL(relativeUrl, 'http://relative'); + if (parsedURL.origin !== 'http://relative') { + return url; + } + } catch (e) { + // url was unparseable + return url; + } + + return `${options.replacementStr}${relativeUrl}`; +}; + +export = absoluteToTransformReady; diff --git a/packages/url-utils/lib/utils/relative-to-absolute.ts b/packages/url-utils/lib/utils/relative-to-absolute.ts new file mode 100644 index 000000000..71778d3d5 --- /dev/null +++ b/packages/url-utils/lib/utils/relative-to-absolute.ts @@ -0,0 +1,100 @@ +// require the whatwg compatible URL library (same behaviour in node and browser) +import {URL} from 'url'; +import urlJoin = require('./url-join'); + +// 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 +// actually treated as subdirectory-relative. This means that it's possible to +// migrate from a root config to a subdirectory config without migrating data +// in the database, _however_ that means that the database will now have a mix +// of path styles (/content/image.png and /subdir/content/image.png). To handle +// this when all root-relative paths are treated as subdir-relative we have to +// rely on subdirectory deduplication. + +interface RelativeToAbsoluteOptions { + assetsOnly?: boolean; + staticImageUrlPrefix?: string; + secure?: boolean; +} + +/** + * Convert a root-relative path to an absolute URL based on the supplied root. + * Will _only_ convert root-relative urls (/some/path not some/path) + * + * @param {string} path + * @param {string} rootUrl + * @param {string} itemPath + * @param {object} options + * @returns {string} The passed in url or an absolute URL using + */ +const relativeToAbsolute = function relativeToAbsolute(path: string, rootUrl: string, itemPath?: string | RelativeToAbsoluteOptions | null, _options?: RelativeToAbsoluteOptions): 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; + } + + // 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; + } + + const defaultOptions: RelativeToAbsoluteOptions = { + assetsOnly: false, + staticImageUrlPrefix: 'content/images' + }; + const options = Object.assign({}, defaultOptions, _options); + + // 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!); + if (!path.match(staticImageUrlPrefixRegex)) { + return path; + } + } + + // if URL is absolute return it as-is + try { + const parsed = new URL(path, 'http://relative'); + + if (parsed.origin !== 'http://relative') { + return path; + } + + // Do not convert protocol relative URLs + if (path.lastIndexOf('//', 0) === 0) { + return path; + } + } catch (e) { + return path; + } + + // return the path as-is if it's a pure hash param + if (path.startsWith('#')) { + return path; + } + + // return the path as-is if it's not root-relative and we have no itemPath + if (!itemPath && !path.match(/^\//)) { + return path; + } + + // force root to always have a trailing-slash for consistent behaviour + if (!rootUrl.endsWith('/')) { + rootUrl = `${rootUrl}/`; + } + + const parsedRootUrl = new URL(rootUrl); + const basePath = path.startsWith('/') ? '' : itemPath || ''; + const fullPath = urlJoin([parsedRootUrl.pathname, basePath, path], {rootUrl}); + const absoluteUrl = new URL(fullPath, rootUrl); + + if (options.secure) { + absoluteUrl.protocol = 'https:'; + } + + return absoluteUrl.toString(); +}; + +export = relativeToAbsolute; diff --git a/packages/url-utils/lib/utils/replace-permalink.ts b/packages/url-utils/lib/utils/replace-permalink.ts new file mode 100644 index 000000000..9a21e7e62 --- /dev/null +++ b/packages/url-utils/lib/utils/replace-permalink.ts @@ -0,0 +1,59 @@ +import moment = require('moment-timezone'); + +interface Resource { + published_at?: string | Date; + slug: string; + id: string | number; + primary_author?: { + slug: string; + }; + primary_tag?: { + slug: string; + }; +} + +/** + * creates the url path for a post based on blog timezone and permalink pattern + */ +function replacePermalink(permalink: string, resource: Resource, timezone = 'UTC'): string { + const output = permalink; + const primaryTagFallback = 'all'; + const publishedAtMoment = moment.tz(resource.published_at || Date.now(), timezone); + const permalinkLookUp: Record string> = { + year: function () { + return publishedAtMoment.format('YYYY'); + }, + month: function () { + return publishedAtMoment.format('MM'); + }, + day: function () { + return publishedAtMoment.format('DD'); + }, + author: function () { + return resource.primary_author!.slug; + }, + primary_author: function () { + return resource.primary_author ? resource.primary_author.slug : primaryTagFallback; + }, + primary_tag: function () { + return resource.primary_tag ? resource.primary_tag.slug : primaryTagFallback; + }, + slug: function () { + return resource.slug; + }, + id: function () { + return String(resource.id); + } + }; + + // 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 match; + }); +} + +export = replacePermalink; diff --git a/packages/url-utils/lib/utils/url-join.ts b/packages/url-utils/lib/utils/url-join.ts new file mode 100644 index 000000000..dee270105 --- /dev/null +++ b/packages/url-utils/lib/utils/url-join.ts @@ -0,0 +1,41 @@ +import deduplicateSubdirectory = require('./deduplicate-subdirectory'); + +interface UrlJoinOptions { + rootUrl: string; +} + +/** urlJoin +* Returns a URL/path for internal use in Ghost. +* @param {string[]} parts takes parts and concats those to a valid path/URL. +* @param {Object} options +* @param {string} options.rootUrl used for deduplicating any subdirectories +* @return {string} URL concatinated URL/path of arguments. +*/ +function urlJoin(parts: string[], options: UrlJoinOptions): string { + let prefixDoubleSlash = false; + + // Remove empty item at the beginning + if (parts[0] === '') { + parts.shift(); + } + + // Handle schemeless protocols + if (parts[0].indexOf('//') === 0) { + prefixDoubleSlash = true; + } + + // join the elements using a slash + let url = parts.join('/'); + + // Fix multiple slashes + url = url.replace(/(^|[^:])\/\/+/g, '$1/'); + + // Put the double slash back at the beginning if this was a schemeless protocol + if (prefixDoubleSlash) { + url = url.replace(/^\//, '//'); + } + + return deduplicateSubdirectory(url, options.rootUrl); +} + +export = urlJoin; From 8fce32961552a5f6fd29609aea3511233e106471 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Oct 2025 03:28:14 +0000 Subject: [PATCH 04/14] chore(url-utils): Convert transform-ready utilities to TypeScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Convert relative-to-transform-ready.js to TypeScript - Convert transform-ready-to-absolute.js to TypeScript - Convert transform-ready-to-relative.js to TypeScript - Convert to-transform-ready.js to TypeScript Added proper interfaces for options and type definitions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../lib/utils/relative-to-transform-ready.ts | 50 +++++++++++++++++++ .../url-utils/lib/utils/to-transform-ready.ts | 20 ++++++++ .../lib/utils/transform-ready-to-absolute.ts | 24 +++++++++ .../lib/utils/transform-ready-to-relative.ts | 30 +++++++++++ 4 files changed, 124 insertions(+) create mode 100644 packages/url-utils/lib/utils/relative-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/transform-ready-to-absolute.ts create mode 100644 packages/url-utils/lib/utils/transform-ready-to-relative.ts diff --git a/packages/url-utils/lib/utils/relative-to-transform-ready.ts b/packages/url-utils/lib/utils/relative-to-transform-ready.ts new file mode 100644 index 000000000..e4252d803 --- /dev/null +++ b/packages/url-utils/lib/utils/relative-to-transform-ready.ts @@ -0,0 +1,50 @@ +import {URL} from 'url'; +import relativeToAbsolute = require('./relative-to-absolute'); + +interface RelativeToTransformReadyOptions { + replacementStr?: string; + staticImageUrlPrefix?: string; + assetsOnly?: boolean; + secure?: boolean; +} + +const relativeToTransformReady = function (url: string, root: string, itemPath?: string | RelativeToTransformReadyOptions | null, _options?: RelativeToTransformReadyOptions): string { + // itemPath is optional, if it's an object may be the options param instead + if (typeof itemPath === 'object' && !_options) { + _options = itemPath; + itemPath = null; + } + + const defaultOptions: RelativeToTransformReadyOptions = { + replacementStr: '__GHOST_URL__', + staticImageUrlPrefix: 'content/images' + }; + const overrideOptions: RelativeToTransformReadyOptions = { + secure: false + }; + const options = Object.assign({}, defaultOptions, _options, overrideOptions); + + // convert to absolute + const absoluteUrl = relativeToAbsolute(url, root, itemPath || null, options); + + if (absoluteUrl === url) { + return url; + } + + const rootUrl = 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) { + // replace root with replacement string + const transformedUrl = absoluteUrl + .replace(root, `${options.replacementStr}/`) // always have trailing slash after magic string + .replace(/([^:])\/\//g, '$1/'); + + return transformedUrl; + } + + return url; +}; + +export = relativeToTransformReady; diff --git a/packages/url-utils/lib/utils/to-transform-ready.ts b/packages/url-utils/lib/utils/to-transform-ready.ts new file mode 100644 index 000000000..f58d76608 --- /dev/null +++ b/packages/url-utils/lib/utils/to-transform-ready.ts @@ -0,0 +1,20 @@ +import relativeToAbsolute = require('./relative-to-absolute'); +import absoluteToTransformReady = require('./absolute-to-transform-ready'); + +interface ToTransformReadyOptions { + replacementStr?: string; + staticImageUrlPrefix?: string; + assetsOnly?: boolean; + withoutSubdirectory?: boolean; +} + +function toTransformReady(url: string, siteUrl: string, itemPath?: string | ToTransformReadyOptions | null, options?: ToTransformReadyOptions): string { + if (typeof itemPath === 'object' && !options) { + options = itemPath; + itemPath = null; + } + const absoluteUrl = relativeToAbsolute(url, siteUrl, itemPath || null, options); + return absoluteToTransformReady(absoluteUrl, siteUrl, options); +} + +export = toTransformReady; diff --git a/packages/url-utils/lib/utils/transform-ready-to-absolute.ts b/packages/url-utils/lib/utils/transform-ready-to-absolute.ts new file mode 100644 index 000000000..a7b486f4c --- /dev/null +++ b/packages/url-utils/lib/utils/transform-ready-to-absolute.ts @@ -0,0 +1,24 @@ +function escapeRegExp(string: string): string { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} + +interface TransformReadyToAbsoluteOptions { + replacementStr?: string; +} + +const transformReadyToAbsolute = function (str = '', root: string, _options: TransformReadyToAbsoluteOptions = {}): string { + const defaultOptions: TransformReadyToAbsoluteOptions = { + replacementStr: '__GHOST_URL__' + }; + const options = Object.assign({}, defaultOptions, _options); + + if (!str || str.indexOf(options.replacementStr!) === -1) { + return str; + } + + const replacementRegex = new RegExp(escapeRegExp(options.replacementStr!), 'g'); + + return str.replace(replacementRegex, root.replace(/\/$/, '')); +}; + +export = transformReadyToAbsolute; diff --git a/packages/url-utils/lib/utils/transform-ready-to-relative.ts b/packages/url-utils/lib/utils/transform-ready-to-relative.ts new file mode 100644 index 000000000..903c3285b --- /dev/null +++ b/packages/url-utils/lib/utils/transform-ready-to-relative.ts @@ -0,0 +1,30 @@ +import {URL} from 'url'; + +function escapeRegExp(string: string): string { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} + +interface TransformReadyToRelativeOptions { + replacementStr?: string; +} + +const transformReadyToRelative = function (str = '', root: string, _options: TransformReadyToRelativeOptions = {}): string { + const defaultOptions: TransformReadyToRelativeOptions = { + replacementStr: '__GHOST_URL__' + }; + const options = Object.assign({}, defaultOptions, _options); + + if (!str || str.indexOf(options.replacementStr!) === -1) { + return str; + } + + const rootURL = new URL(root); + // subdir with no trailing slash because we'll always have a trailing slash after the magic string + const subdir = rootURL.pathname.replace(/\/$/, ''); + + const replacementRegex = new RegExp(escapeRegExp(options.replacementStr!), 'g'); + + return str.replace(replacementRegex, subdir); +}; + +export = transformReadyToRelative; From 5dd5584c42dc0f4abbcc0527c7b7a3d996c2e9da Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Oct 2025 03:29:36 +0000 Subject: [PATCH 05/14] chore(url-utils): Convert HTML transformation utilities to TypeScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Convert html-transform.js to TypeScript with proper interfaces - Convert html-relative-to-absolute.js to TypeScript - Convert html-absolute-to-relative.js to TypeScript - Convert html-absolute-to-transform-ready.js to TypeScript - Convert html-relative-to-transform-ready.js to TypeScript - Convert html-to-transform-ready.js to TypeScript Added type definitions for transform functions and options. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../lib/utils/html-absolute-to-relative.ts | 27 +++ .../utils/html-absolute-to-transform-ready.ts | 27 +++ .../lib/utils/html-relative-to-absolute.ts | 24 +++ .../utils/html-relative-to-transform-ready.ts | 36 ++++ .../lib/utils/html-to-transform-ready.ts | 19 +++ .../url-utils/lib/utils/html-transform.ts | 158 ++++++++++++++++++ 6 files changed, 291 insertions(+) create mode 100644 packages/url-utils/lib/utils/html-absolute-to-relative.ts create mode 100644 packages/url-utils/lib/utils/html-absolute-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/html-relative-to-absolute.ts create mode 100644 packages/url-utils/lib/utils/html-relative-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/html-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/html-transform.ts diff --git a/packages/url-utils/lib/utils/html-absolute-to-relative.ts b/packages/url-utils/lib/utils/html-absolute-to-relative.ts new file mode 100644 index 000000000..23e0c89b4 --- /dev/null +++ b/packages/url-utils/lib/utils/html-absolute-to-relative.ts @@ -0,0 +1,27 @@ +import htmlTransform = require('./html-transform'); +import absoluteToRelative = require('./absolute-to-relative'); + +interface HtmlAbsoluteToRelativeOptions { + assetsOnly?: boolean; + ignoreProtocol?: boolean; + staticImageUrlPrefix?: string; + earlyExitMatchStr?: string; +} + +function htmlAbsoluteToRelative(html = '', siteUrl: string, _options?: HtmlAbsoluteToRelativeOptions): string { + const defaultOptions: HtmlAbsoluteToRelativeOptions = {assetsOnly: false, ignoreProtocol: true}; + const options = 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: string, _siteUrl: string, _itemPath: string | null, __options: any) { + return absoluteToRelative(_url, _siteUrl, __options); + }; + + return htmlTransform(html, siteUrl, transformFunction, '', options); +} + +export = htmlAbsoluteToRelative; diff --git a/packages/url-utils/lib/utils/html-absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/html-absolute-to-transform-ready.ts new file mode 100644 index 000000000..9d0b8b7a9 --- /dev/null +++ b/packages/url-utils/lib/utils/html-absolute-to-transform-ready.ts @@ -0,0 +1,27 @@ +import htmlTransform = require('./html-transform'); +import absoluteToTransformReady = require('./absolute-to-transform-ready'); + +interface HtmlAbsoluteToTransformReadyOptions { + assetsOnly?: boolean; + ignoreProtocol?: boolean; + staticImageUrlPrefix?: string; + earlyExitMatchStr?: string; +} + +const htmlAbsoluteToTransformReady = function (html = '', siteUrl: string, _options?: HtmlAbsoluteToTransformReadyOptions): string { + const defaultOptions: HtmlAbsoluteToTransformReadyOptions = {assetsOnly: false, ignoreProtocol: true}; + const options = 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: string, _siteUrl: string, _itemPath: string | null, __options: any) { + return absoluteToTransformReady(_url, _siteUrl, __options); + }; + + return htmlTransform(html, siteUrl, transformFunction, '', options); +}; + +export = htmlAbsoluteToTransformReady; diff --git a/packages/url-utils/lib/utils/html-relative-to-absolute.ts b/packages/url-utils/lib/utils/html-relative-to-absolute.ts new file mode 100644 index 000000000..087b52f0d --- /dev/null +++ b/packages/url-utils/lib/utils/html-relative-to-absolute.ts @@ -0,0 +1,24 @@ +import htmlTransform = require('./html-transform'); +import relativeToAbsolute = require('./relative-to-absolute'); + +interface HtmlRelativeToAbsoluteOptions { + assetsOnly?: boolean; + secure?: boolean; + staticImageUrlPrefix?: string; + earlyExitMatchStr?: string; +} + +function htmlRelativeToAbsolute(html = '', siteUrl: string, itemPath: string | HtmlRelativeToAbsoluteOptions | null, _options?: HtmlRelativeToAbsoluteOptions): string { + const defaultOptions: HtmlRelativeToAbsoluteOptions = {assetsOnly: false, secure: false}; + const options = 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='; + if (options.assetsOnly) { + options.earlyExitMatchStr = options.staticImageUrlPrefix; + } + + return htmlTransform(html, siteUrl, relativeToAbsolute, itemPath as string | null, options); +} + +export = htmlRelativeToAbsolute; diff --git a/packages/url-utils/lib/utils/html-relative-to-transform-ready.ts b/packages/url-utils/lib/utils/html-relative-to-transform-ready.ts new file mode 100644 index 000000000..70b1d87e6 --- /dev/null +++ b/packages/url-utils/lib/utils/html-relative-to-transform-ready.ts @@ -0,0 +1,36 @@ +import htmlTransform = require('./html-transform'); +import relativeToTransformReady = require('./relative-to-transform-ready'); + +interface HtmlRelativeToTransformReadyOptions { + replacementStr?: string; + assetsOnly?: boolean; + staticImageUrlPrefix?: string; + secure?: boolean; + earlyExitMatchStr?: string; +} + +const htmlRelativeToTransformReady = function (html = '', root: string, itemPath?: string | HtmlRelativeToTransformReadyOptions | null, _options?: HtmlRelativeToTransformReadyOptions): string { + // itemPath is optional, if it's an object may be the options param instead + if (typeof itemPath === 'object' && !_options) { + _options = itemPath; + itemPath = null; + } + + const defaultOptions: HtmlRelativeToTransformReadyOptions = { + replacementStr: '__GHOST_URL__' + }; + const overrideOptions: HtmlRelativeToTransformReadyOptions = { + secure: false + }; + const options = Object.assign({}, defaultOptions, _options, overrideOptions); + + // exit early and avoid parsing if the content does not contain an attribute we might transform + options.earlyExitMatchStr = 'href=|src=|srcset='; + if (options.assetsOnly) { + options.earlyExitMatchStr = options.staticImageUrlPrefix; + } + + return htmlTransform(html, root, relativeToTransformReady, itemPath as string | null, options); +}; + +export = htmlRelativeToTransformReady; diff --git a/packages/url-utils/lib/utils/html-to-transform-ready.ts b/packages/url-utils/lib/utils/html-to-transform-ready.ts new file mode 100644 index 000000000..049397cf3 --- /dev/null +++ b/packages/url-utils/lib/utils/html-to-transform-ready.ts @@ -0,0 +1,19 @@ +import htmlRelativeToAbsolute = require('./html-relative-to-absolute'); +import htmlAbsoluteToTransformReady = require('./html-absolute-to-transform-ready'); + +interface HtmlToTransformReadyOptions { + assetsOnly?: boolean; + staticImageUrlPrefix?: string; + replacementStr?: string; +} + +function htmlToTransformReady(html: string, siteUrl: string, itemPath?: string | HtmlToTransformReadyOptions | null, options?: HtmlToTransformReadyOptions): string { + if (typeof itemPath === 'object' && !options) { + options = itemPath; + itemPath = null; + } + const absolute = htmlRelativeToAbsolute(html, siteUrl, itemPath || null, options); + return htmlAbsoluteToTransformReady(absolute, siteUrl, options); +} + +export = htmlToTransformReady; diff --git a/packages/url-utils/lib/utils/html-transform.ts b/packages/url-utils/lib/utils/html-transform.ts new file mode 100644 index 000000000..8263a141a --- /dev/null +++ b/packages/url-utils/lib/utils/html-transform.ts @@ -0,0 +1,158 @@ +function escapeRegExp(string: string): string { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} + +function extractSrcsetUrls(srcset = ''): string[] { + return srcset.split(',').map((part) => { + return part.trim().split(/\s+/)[0]; + }); +} + +function extractStyleUrls(style = ''): string[] { + const urls: string[] = []; + const regex = /url\(['|"]([^)]+)['|"]\)/g; + let match; + + while ((match = regex.exec(style)) !== null) { + urls.push(match[1]); + } + + return urls; +} + +interface HtmlTransformOptions { + assetsOnly?: boolean; + secure?: boolean; + earlyExitMatchStr?: string; +} + +type TransformFunction = (url: string, siteUrl: string, itemPath: string | null, options: HtmlTransformOptions) => string; + +interface Replacement { + name: string; + originalValue: string; + transformedValue?: string; + skip?: boolean; +} + +function htmlTransform(html = '', siteUrl: string, transformFunction: TransformFunction, itemPath: string | null, _options?: HtmlTransformOptions): string { + const defaultOptions: HtmlTransformOptions = {assetsOnly: false, secure: false}; + const options = Object.assign({}, defaultOptions, _options || {}); + + if (!html || (options.earlyExitMatchStr && !html.match(new RegExp(options.earlyExitMatchStr)))) { + return html; + } + + const cheerio = require('cheerio'); + const htmlContent = cheerio.load(html, {decodeEntities: false}); + + // replacements is keyed with the attr name + original relative value so + // that we can implement skips for untouchable urls + // + // replacements = { + // 'href="/test"': [ + // {name: 'href', originalValue: '/test', absoluteValue: '.../test'}, + // {name: 'href', originalValue: '/test', skip: true}, // found inside a element + // {name: 'href', originalValue: '/test', absoluteValue: '.../test'}, + // ] + // } + const replacements: Record = {}; + + function addReplacement(replacement: Replacement) { + const key = `${replacement.name}="${replacement.originalValue}"`; + + if (!replacements[key]) { + replacements[key] = []; + } + + replacements[key].push(replacement); + } + + // find all of the relative url attributes that we care about + ['href', 'src', 'srcset', 'style'].forEach((attributeName) => { + htmlContent('[' + attributeName + ']').each((ix: number, el: any) => { + // ignore elems and html inside of elements + if (el.name === 'stream' || htmlContent(el).closest('code').length) { + addReplacement({ + name: attributeName, + originalValue: htmlContent(el).attr(attributeName), + skip: true + }); + return; + } + + el = htmlContent(el); + const originalValue = el.attr(attributeName); + + if (attributeName === 'srcset' || attributeName === 'style') { + let urls: string[]; + + if (attributeName === 'srcset') { + urls = extractSrcsetUrls(originalValue); + } else { + urls = extractStyleUrls(originalValue); + } + const absoluteUrls = urls.map(url => transformFunction(url, siteUrl, itemPath, options)); + let transformedValue = originalValue; + + urls.forEach((url, i) => { + if (absoluteUrls[i]) { + let regex = new RegExp(escapeRegExp(url), 'g'); + transformedValue = transformedValue.replace(regex, absoluteUrls[i]); + } + }); + + if (transformedValue !== originalValue) { + addReplacement({ + name: attributeName, + originalValue, + transformedValue + }); + } + } else { + const transformedValue = transformFunction(originalValue, siteUrl, itemPath, options); + + if (transformedValue !== originalValue) { + addReplacement({ + name: attributeName, + originalValue, + transformedValue + }); + } + } + }); + }); + + // Loop over all replacements and use a regex to replace urls in the original html string. + // Allows indentation and formatting to be kept compared to using DOM manipulation and render + for (const [, attrs] of Object.entries(replacements)) { + let skipCount = 0; + + attrs.forEach(({skip, name, originalValue, transformedValue}) => { + if (skip) { + skipCount += 1; + 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 + // eslint-disable-next-line no-useless-escape + const regex = new RegExp(`<[a-zA-Z][^>]*?(${name}=['"](${escapeRegExp(originalValue)})['"]).*?>`, 'gs'); + + let matchCount = 0; + html = html.replace(regex, (match, p1) => { + let result = match; + if (matchCount === skipCount) { + result = match.replace(p1, p1.replace(originalValue, transformedValue!)); + } + matchCount += 1; + return result; + }); + }); + } + + return html; +} + +export = htmlTransform; From 9c1c58dba9437de55a4286db2d783c59a6ebc426 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Oct 2025 03:30:40 +0000 Subject: [PATCH 06/14] chore(url-utils): Convert Markdown transformation utilities to TypeScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Convert markdown-transform.js to TypeScript with proper interfaces - Convert markdown-relative-to-absolute.js to TypeScript - Convert markdown-absolute-to-relative.js to TypeScript - Convert markdown-absolute-to-transform-ready.js to TypeScript - Convert markdown-relative-to-transform-ready.js to TypeScript - Convert markdown-to-transform-ready.js to TypeScript Added type definitions for transform functions and remark AST nodes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../utils/markdown-absolute-to-relative.ts | 32 +++++ .../markdown-absolute-to-transform-ready.ts | 32 +++++ .../utils/markdown-relative-to-absolute.ts | 28 +++++ .../markdown-relative-to-transform-ready.ts | 28 +++++ .../lib/utils/markdown-to-transform-ready.ts | 18 +++ .../url-utils/lib/utils/markdown-transform.ts | 117 ++++++++++++++++++ 6 files changed, 255 insertions(+) create mode 100644 packages/url-utils/lib/utils/markdown-absolute-to-relative.ts create mode 100644 packages/url-utils/lib/utils/markdown-absolute-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/markdown-relative-to-absolute.ts create mode 100644 packages/url-utils/lib/utils/markdown-relative-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/markdown-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/markdown-transform.ts diff --git a/packages/url-utils/lib/utils/markdown-absolute-to-relative.ts b/packages/url-utils/lib/utils/markdown-absolute-to-relative.ts new file mode 100644 index 000000000..fa5988ffc --- /dev/null +++ b/packages/url-utils/lib/utils/markdown-absolute-to-relative.ts @@ -0,0 +1,32 @@ +import markdownTransform = require('./markdown-transform'); +import absoluteToRelative = require('./absolute-to-relative'); +import htmlAbsoluteToRelative = require('./html-absolute-to-relative'); + +interface MarkdownAbsoluteToRelativeOptions { + assetsOnly?: boolean; + ignoreProtocol?: boolean; + staticImageUrlPrefix?: string; + earlyExitMatchStr?: string; +} + +function markdownAbsoluteToRelative(markdown = '', siteUrl: string, _options: MarkdownAbsoluteToRelativeOptions = {}): string { + const defaultOptions: MarkdownAbsoluteToRelativeOptions = {assetsOnly: false, ignoreProtocol: true}; + const options = 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: string, _siteUrl: string, _itemPath: string | null, __options: any) { + return htmlAbsoluteToRelative(_url, _siteUrl, __options); + }, + url(_url: string, _siteUrl: string, _itemPath: string | null, __options: any) { + return absoluteToRelative(_url, _siteUrl, __options); + } + }; + + return markdownTransform(markdown, siteUrl, transformFunctions, '', options); +} + +export = markdownAbsoluteToRelative; diff --git a/packages/url-utils/lib/utils/markdown-absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/markdown-absolute-to-transform-ready.ts new file mode 100644 index 000000000..83d39aac6 --- /dev/null +++ b/packages/url-utils/lib/utils/markdown-absolute-to-transform-ready.ts @@ -0,0 +1,32 @@ +import markdownTransform = require('./markdown-transform'); +import absoluteToTransformReady = require('./absolute-to-transform-ready'); +import htmlAbsoluteToTransformReady = require('./html-absolute-to-transform-ready'); + +interface MarkdownAbsoluteToTransformReadyOptions { + assetsOnly?: boolean; + ignoreProtocol?: boolean; + staticImageUrlPrefix?: string; + earlyExitMatchStr?: string; +} + +function markdownAbsoluteToTransformReady(markdown = '', siteUrl: string, _options: MarkdownAbsoluteToTransformReadyOptions = {}): string { + const defaultOptions: MarkdownAbsoluteToTransformReadyOptions = {assetsOnly: false, ignoreProtocol: true}; + const options = Object.assign({}, defaultOptions, _options); + + options.earlyExitMatchStr = options.ignoreProtocol ? siteUrl.replace(/http:|https:/, '') : siteUrl; + options.earlyExitMatchStr = options.earlyExitMatchStr.replace(/\/$/, ''); + + // need to ignore itemPath because absoluteToTransformReady functions doen't take that option + const transformFunctions = { + html(_url: string, _siteUrl: string, _itemPath: string | null, __options: any) { + return htmlAbsoluteToTransformReady(_url, _siteUrl, __options); + }, + url(_url: string, _siteUrl: string, _itemPath: string | null, __options: any) { + return absoluteToTransformReady(_url, _siteUrl, __options); + } + }; + + return markdownTransform(markdown, siteUrl, transformFunctions, '', options); +} + +export = markdownAbsoluteToTransformReady; diff --git a/packages/url-utils/lib/utils/markdown-relative-to-absolute.ts b/packages/url-utils/lib/utils/markdown-relative-to-absolute.ts new file mode 100644 index 000000000..c0845cdf4 --- /dev/null +++ b/packages/url-utils/lib/utils/markdown-relative-to-absolute.ts @@ -0,0 +1,28 @@ +import markdownTransform = require('./markdown-transform'); +import htmlRelativeToAbsolute = require('./html-relative-to-absolute'); +import relativeToAbsolute = require('./relative-to-absolute'); + +interface MarkdownRelativeToAbsoluteOptions { + assetsOnly?: boolean; + staticImageUrlPrefix?: string; + earlyExitMatchStr?: string; +} + +function markdownRelativeToAbsolute(markdown = '', siteUrl: string, itemPath: string | MarkdownRelativeToAbsoluteOptions | null, _options: MarkdownRelativeToAbsoluteOptions = {}): string { + const defaultOptions: MarkdownRelativeToAbsoluteOptions = {assetsOnly: false}; + const options = Object.assign({}, defaultOptions, _options); + + options.earlyExitMatchStr = '\\]\\([^\\s\\)]|href=|src=|srcset='; + if (options.assetsOnly) { + options.earlyExitMatchStr = options.staticImageUrlPrefix; + } + + const transformFunctions = { + html: htmlRelativeToAbsolute, + url: relativeToAbsolute + }; + + return markdownTransform(markdown, siteUrl, transformFunctions, itemPath as string | null, options); +} + +export = markdownRelativeToAbsolute; diff --git a/packages/url-utils/lib/utils/markdown-relative-to-transform-ready.ts b/packages/url-utils/lib/utils/markdown-relative-to-transform-ready.ts new file mode 100644 index 000000000..00dd4e719 --- /dev/null +++ b/packages/url-utils/lib/utils/markdown-relative-to-transform-ready.ts @@ -0,0 +1,28 @@ +import markdownTransform = require('./markdown-transform'); +import htmlRelativeToTransformReady = require('./html-relative-to-transform-ready'); +import relativeToTransformReady = require('./relative-to-transform-ready'); + +interface MarkdownRelativeToTransformReadyOptions { + assetsOnly?: boolean; + staticImageUrlPrefix?: string; + earlyExitMatchStr?: string; +} + +function markdownRelativeToTransformReady(markdown = '', siteUrl: string, itemPath: string | MarkdownRelativeToTransformReadyOptions | null, _options: MarkdownRelativeToTransformReadyOptions = {}): string { + const defaultOptions: MarkdownRelativeToTransformReadyOptions = {assetsOnly: false}; + const options = Object.assign({}, defaultOptions, _options); + + options.earlyExitMatchStr = '\\]\\([^\\s\\)]|href=|src=|srcset='; + if (options.assetsOnly) { + options.earlyExitMatchStr = options.staticImageUrlPrefix; + } + + const transformFunctions = { + html: htmlRelativeToTransformReady, + url: relativeToTransformReady + }; + + return markdownTransform(markdown, siteUrl, transformFunctions, itemPath as string | null, options); +} + +export = markdownRelativeToTransformReady; diff --git a/packages/url-utils/lib/utils/markdown-to-transform-ready.ts b/packages/url-utils/lib/utils/markdown-to-transform-ready.ts new file mode 100644 index 000000000..50284654d --- /dev/null +++ b/packages/url-utils/lib/utils/markdown-to-transform-ready.ts @@ -0,0 +1,18 @@ +import markdownRelativeToAbsolute = require('./markdown-relative-to-absolute'); +import markdownAbsoluteToTransformReady = require('./markdown-absolute-to-transform-ready'); + +interface MarkdownToTransformReadyOptions { + assetsOnly?: boolean; + staticImageUrlPrefix?: string; +} + +function markdownToTransformReady(markdown: string, siteUrl: string, itemPath?: string | MarkdownToTransformReadyOptions | null, options?: MarkdownToTransformReadyOptions): string { + if (typeof itemPath === 'object' && !options) { + options = itemPath; + itemPath = null; + } + const absolute = markdownRelativeToAbsolute(markdown, siteUrl, itemPath || null, options); + return markdownAbsoluteToTransformReady(absolute, siteUrl, options); +} + +export = markdownToTransformReady; diff --git a/packages/url-utils/lib/utils/markdown-transform.ts b/packages/url-utils/lib/utils/markdown-transform.ts new file mode 100644 index 000000000..9949d42fb --- /dev/null +++ b/packages/url-utils/lib/utils/markdown-transform.ts @@ -0,0 +1,117 @@ +let remark: any; +const footnotes = require('remark-footnotes'); +const visit = require('unist-util-visit'); + +function replaceLast(find: string, replace: string, str: string): string { + const lastIndex = str.lastIndexOf(find); + + if (lastIndex === -1) { + return str; + } + + const begin = str.substring(0, lastIndex); + const end = str.substring(lastIndex + find.length); + + return begin + replace + end; +} + +interface MarkdownTransformOptions { + assetsOnly?: boolean; + ignoreProtocol?: boolean; + earlyExitMatchStr?: string; + staticImageUrlPrefix?: string; +} + +interface TransformFunctions { + html: (value: string, siteUrl: string, itemPath: string | null, options: MarkdownTransformOptions) => string; + url: (url: string, siteUrl: string, itemPath: string | null, options: MarkdownTransformOptions) => string; +} + +interface Replacement { + old: string; + new: string; + start: number; + end: number; +} + +function markdownTransform(markdown = '', siteUrl: string, transformFunctions: TransformFunctions, itemPath: string | null, _options: MarkdownTransformOptions = {}): string { + const defaultOptions: MarkdownTransformOptions = {assetsOnly: false, ignoreProtocol: true}; + const options = Object.assign({}, defaultOptions, _options); + + if (!markdown || (options.earlyExitMatchStr && !markdown.match(new RegExp(options.earlyExitMatchStr)))) { + return markdown; + } + + const replacements: Replacement[] = []; + + if (!remark) { + remark = require('remark'); + } + + const tree = remark() + .use({settings: {commonmark: true}}) + .use(footnotes, {inlineNotes: true}) + .parse(markdown); + + visit(tree, ['link', 'image', 'html'], (node: any) => { + if (node.type === 'html' && node.value.match(/src|srcset|href/)) { + const oldValue = node.value; + const newValue = transformFunctions.html(node.value, siteUrl, itemPath, options); + + if (newValue !== oldValue) { + replacements.push({ + old: oldValue, + new: newValue, + start: node.position.start.offset, + end: node.position.end.offset + }); + } + } + + if (node.type === 'link' || node.type === 'image') { + const oldValue = node.url; + const newValue = transformFunctions.url(node.url, siteUrl, itemPath, options); + + if (newValue !== oldValue) { + replacements.push({ + old: oldValue, + new: newValue, + start: node.position.start.offset, + end: node.position.end.offset + }); + } + } + }); + + let result = markdown; + let offsetAdjustment = 0; + let nestedAdjustment = 0; + + replacements.forEach((replacement, i) => { + const original = markdown.slice(replacement.start, replacement.end); + // only transform last occurrence of the old string because markdown links and images + // have urls at the end and we see replacements for outermost nested nodes first + const transformed = replaceLast(replacement.old, replacement.new, original); + + let before = result.slice(0, replacement.start + offsetAdjustment); + let after = result.slice(replacement.end + offsetAdjustment, result.length); + + result = before + transformed + after; + + // adjust offset according to new lengths + const nextReplacement = replacements[i + 1]; + const adjustment = transformed.length - original.length; + + if (nextReplacement && nextReplacement.start < replacement.end) { + // next replacement is nested, do not apply any offset adjustments until we're out of nesting + nestedAdjustment = nestedAdjustment + adjustment; + } else { + offsetAdjustment = offsetAdjustment + adjustment + nestedAdjustment; + nestedAdjustment = 0; + } + }); + + return result; +} + +export = markdownTransform; From 91df348e47141ab604b75e63f30efc118ca99684 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Oct 2025 03:40:53 +0000 Subject: [PATCH 07/14] chore(url-utils): Convert Mobiledoc and Lexical utilities to TypeScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mobiledoc utilities: - Convert mobiledoc-transform.js to TypeScript - Convert mobiledoc-to-transform-ready.js to TypeScript - Convert mobiledoc-relative-to-absolute.js to TypeScript - Convert mobiledoc-absolute-to-relative.js to TypeScript - Convert mobiledoc-relative-to-transform-ready.js to TypeScript - Convert mobiledoc-absolute-to-transform-ready.js to TypeScript Lexical utilities: - Convert lexical-transform.js to TypeScript - Convert lexical-to-transform-ready.js to TypeScript - Convert lexical-relative-to-absolute.js to TypeScript - Convert lexical-absolute-to-relative.js to TypeScript - Convert lexical-relative-to-transform-ready.js to TypeScript - Convert lexical-absolute-to-transform-ready.js to TypeScript Added proper type definitions for transform functions, options interfaces, and JSON structures. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../lib/utils/lexical-absolute-to-relative.ts | 23 +++++ .../lexical-absolute-to-transform-ready.ts | 23 +++++ .../lib/utils/lexical-relative-to-absolute.ts | 19 ++++ .../lexical-relative-to-transform-ready.ts | 19 ++++ .../lib/utils/lexical-to-transform-ready.ts | 20 ++++ .../url-utils/lib/utils/lexical-transform.ts | 94 +++++++++++++++++++ .../utils/mobiledoc-absolute-to-relative.ts | 22 +++++ .../mobiledoc-absolute-to-transform-ready.ts | 22 +++++ .../utils/mobiledoc-relative-to-absolute.ts | 18 ++++ .../mobiledoc-relative-to-transform-ready.ts | 18 ++++ .../lib/utils/mobiledoc-to-transform-ready.ts | 24 +++++ .../lib/utils/mobiledoc-transform.ts | 69 ++++++++++++++ 12 files changed, 371 insertions(+) create mode 100644 packages/url-utils/lib/utils/lexical-absolute-to-relative.ts create mode 100644 packages/url-utils/lib/utils/lexical-absolute-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/lexical-relative-to-absolute.ts create mode 100644 packages/url-utils/lib/utils/lexical-relative-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/lexical-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/lexical-transform.ts create mode 100644 packages/url-utils/lib/utils/mobiledoc-absolute-to-relative.ts create mode 100644 packages/url-utils/lib/utils/mobiledoc-absolute-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/mobiledoc-relative-to-absolute.ts create mode 100644 packages/url-utils/lib/utils/mobiledoc-relative-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/mobiledoc-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/mobiledoc-transform.ts diff --git a/packages/url-utils/lib/utils/lexical-absolute-to-relative.ts b/packages/url-utils/lib/utils/lexical-absolute-to-relative.ts new file mode 100644 index 000000000..560fc467f --- /dev/null +++ b/packages/url-utils/lib/utils/lexical-absolute-to-relative.ts @@ -0,0 +1,23 @@ +import absoluteToRelative = require('./absolute-to-relative'); +import lexicalTransform = require('./lexical-transform'); + +interface LexicalAbsoluteToRelativeOptions { + assetsOnly?: boolean; + secure?: boolean; + nodes?: any[]; + transformMap?: Record string>>; +} + +function lexicalAbsoluteToRelative(serializedLexical: string, siteUrl: string, _options: LexicalAbsoluteToRelativeOptions = {}): string { + const defaultOptions: LexicalAbsoluteToRelativeOptions = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; + const overrideOptions = {siteUrl, transformType: 'absoluteToRelative'}; + const options = Object.assign({}, defaultOptions, _options, overrideOptions); + + const transformFunction = function (_url: string, _siteUrl: string, _itemPath: string | null, __options: any) { + return absoluteToRelative(_url, _siteUrl, __options); + }; + + return lexicalTransform(serializedLexical, siteUrl, transformFunction, null, options); +} + +export = lexicalAbsoluteToRelative; diff --git a/packages/url-utils/lib/utils/lexical-absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/lexical-absolute-to-transform-ready.ts new file mode 100644 index 000000000..acf4cebb1 --- /dev/null +++ b/packages/url-utils/lib/utils/lexical-absolute-to-transform-ready.ts @@ -0,0 +1,23 @@ +import absoluteToTransformReady = require('./absolute-to-transform-ready'); +import lexicalTransform = require('./lexical-transform'); + +interface LexicalAbsoluteToTransformReadyOptions { + assetsOnly?: boolean; + secure?: boolean; + nodes?: any[]; + transformMap?: Record string>>; +} + +function lexicalAbsoluteToTransformReady(serializedLexical: string, siteUrl: string, _options: LexicalAbsoluteToTransformReadyOptions = {}): string { + const defaultOptions: LexicalAbsoluteToTransformReadyOptions = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; + const overrideOptions = {siteUrl, transformType: 'toTransformReady'}; + const options = Object.assign({}, defaultOptions, _options, overrideOptions); + + const transformFunction = function (_url: string, _siteUrl: string, _itemPath: string | null, __options: any) { + return absoluteToTransformReady(_url, _siteUrl, __options); + }; + + return lexicalTransform(serializedLexical, siteUrl, transformFunction, null, options); +} + +export = lexicalAbsoluteToTransformReady; diff --git a/packages/url-utils/lib/utils/lexical-relative-to-absolute.ts b/packages/url-utils/lib/utils/lexical-relative-to-absolute.ts new file mode 100644 index 000000000..e32c0c819 --- /dev/null +++ b/packages/url-utils/lib/utils/lexical-relative-to-absolute.ts @@ -0,0 +1,19 @@ +import relativeToAbsolute = require('./relative-to-absolute'); +import lexicalTransform = require('./lexical-transform'); + +interface LexicalRelativeToAbsoluteOptions { + assetsOnly?: boolean; + secure?: boolean; + nodes?: any[]; + transformMap?: Record string>>; +} + +function lexicalRelativeToAbsolute(serializedLexical: string, siteUrl: string, itemPath: string | null, _options: LexicalRelativeToAbsoluteOptions = {}): string { + const defaultOptions: LexicalRelativeToAbsoluteOptions = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; + const overrideOptions = {siteUrl, itemPath, transformType: 'relativeToAbsolute'}; + const options = Object.assign({}, defaultOptions, _options, overrideOptions); + + return lexicalTransform(serializedLexical, siteUrl, relativeToAbsolute, itemPath, options); +} + +export = lexicalRelativeToAbsolute; diff --git a/packages/url-utils/lib/utils/lexical-relative-to-transform-ready.ts b/packages/url-utils/lib/utils/lexical-relative-to-transform-ready.ts new file mode 100644 index 000000000..aed4a6ff5 --- /dev/null +++ b/packages/url-utils/lib/utils/lexical-relative-to-transform-ready.ts @@ -0,0 +1,19 @@ +import relativeToTransformReady = require('./relative-to-transform-ready'); +import lexicalTransform = require('./lexical-transform'); + +interface LexicalRelativeToTransformReadyOptions { + assetsOnly?: boolean; + secure?: boolean; + nodes?: any[]; + transformMap?: Record string>>; +} + +function lexicalRelativeToTransformReady(serializedLexical: string, siteUrl: string, itemPath: string | null, _options: LexicalRelativeToTransformReadyOptions = {}): string { + const defaultOptions: LexicalRelativeToTransformReadyOptions = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; + const overrideOptions = {siteUrl, transformType: 'toTransformReady'}; + const options = Object.assign({}, defaultOptions, _options, overrideOptions); + + return lexicalTransform(serializedLexical, siteUrl, relativeToTransformReady, itemPath, options); +} + +export = lexicalRelativeToTransformReady; diff --git a/packages/url-utils/lib/utils/lexical-to-transform-ready.ts b/packages/url-utils/lib/utils/lexical-to-transform-ready.ts new file mode 100644 index 000000000..4679e590f --- /dev/null +++ b/packages/url-utils/lib/utils/lexical-to-transform-ready.ts @@ -0,0 +1,20 @@ +import lexicalRelativeToAbsolute = require('./lexical-relative-to-absolute'); +import lexicalAbsoluteToTransformReady = require('./lexical-absolute-to-transform-ready'); + +interface LexicalToTransformReadyOptions { + assetsOnly?: boolean; + secure?: boolean; + nodes?: any[]; + transformMap?: Record string>>; +} + +function lexicalToTransformReady(lexical: string, siteUrl: string, itemPath?: string | LexicalToTransformReadyOptions | null, options?: LexicalToTransformReadyOptions): string { + if (typeof itemPath === 'object' && !options) { + options = itemPath; + itemPath = null; + } + const absolute = lexicalRelativeToAbsolute(lexical, siteUrl, itemPath as string | null, options); + return lexicalAbsoluteToTransformReady(absolute, siteUrl, options); +} + +export = lexicalToTransformReady; diff --git a/packages/url-utils/lib/utils/lexical-transform.ts b/packages/url-utils/lib/utils/lexical-transform.ts new file mode 100644 index 000000000..d380bca27 --- /dev/null +++ b/packages/url-utils/lib/utils/lexical-transform.ts @@ -0,0 +1,94 @@ +import * as _ from 'lodash'; + +// options.transformMap = { +// relativeToAbsolute: { +// url: (url, siteUrl, itemPath, options) => 'transformedUrl', +// html: (html, siteUrl, itemPath, options) => 'transformedHtml', +// } +// } +// options.transformType = 'relativeToAbsolute' + +interface LexicalNode { + getType(): string; + urlTransformMap?: Record>; +} + +interface LexicalTransformOptions { + assetsOnly?: boolean; + secure?: boolean; + nodes?: LexicalNode[]; + transformMap?: Record string>>; + transformType?: string; + siteUrl?: string; + itemPath?: string | null; +} + +type TransformFunction = (url: string, siteUrl: string, itemPath: string | null, options: LexicalTransformOptions) => string; + +function lexicalTransform(serializedLexical: string, siteUrl: string, transformFunction: TransformFunction, itemPath: string | null, _options: LexicalTransformOptions = {}): string { + const defaultOptions: LexicalTransformOptions = {assetsOnly: false, secure: false, nodes: [], transformMap: {}}; + const options = Object.assign({}, defaultOptions, _options, {siteUrl, itemPath}); + + if (!serializedLexical) { + return serializedLexical; + } + + // function only accepts serialized lexical so there's no chance of accidentally + // modifying pass-by-reference objects + const lexical: any = JSON.parse(serializedLexical); + + if (!lexical?.root?.children) { + return serializedLexical; + } + + // create a map of node types to urlTransformMap objects + // e.g. {'image': {src: 'url', caption: 'html'} + const nodeMap = new Map>>(); + options.nodes!.forEach(node => node.urlTransformMap && nodeMap.set(node.getType(), node.urlTransformMap)); + + const transformProperty = function (obj: any, propertyPath: string, transform: string | Record) { + const propertyValue = _.get(obj, propertyPath); + + if (Array.isArray(propertyValue)) { + propertyValue.forEach((item: any) => { + // 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 as Record).forEach(([itemPropertyPath, itemTransform]) => { + transformProperty(item, itemPropertyPath, itemTransform); + }); + }); + + return; + } + + if (propertyValue) { + _.set(obj, propertyPath, options.transformMap![options.transformType!][transform as string](propertyValue)); + } + }; + + // recursively walk the Lexical node tree transforming any card data properties and links + const transformChildren = function (children: any[]) { + 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) { + child.url = transformFunction(child.url, siteUrl, itemPath, options); + } + + if (child.children) { + transformChildren(child.children); + } + } + }; + + transformChildren(lexical.root.children); + + return JSON.stringify(lexical); +} + +export = lexicalTransform; diff --git a/packages/url-utils/lib/utils/mobiledoc-absolute-to-relative.ts b/packages/url-utils/lib/utils/mobiledoc-absolute-to-relative.ts new file mode 100644 index 000000000..21bacd7e2 --- /dev/null +++ b/packages/url-utils/lib/utils/mobiledoc-absolute-to-relative.ts @@ -0,0 +1,22 @@ +import absoluteToRelative = require('./absolute-to-relative'); +import mobiledocTransform = require('./mobiledoc-transform'); + +interface MobiledocAbsoluteToRelativeOptions { + assetsOnly?: boolean; + secure?: boolean; + cardTransformers?: any[]; +} + +function mobiledocAbsoluteToRelative(serializedMobiledoc: string, siteUrl: string, _options: MobiledocAbsoluteToRelativeOptions = {}): string { + const defaultOptions: MobiledocAbsoluteToRelativeOptions = {assetsOnly: false, secure: false, cardTransformers: []}; + const overrideOptions = {siteUrl, transformType: 'absoluteToRelative'}; + const options = Object.assign({}, defaultOptions, _options, overrideOptions); + + const transformFunction = function (_url: string, _siteUrl: string, _itemPath: string | null, __options: any): string { + return absoluteToRelative(_url, _siteUrl, __options); + }; + + return mobiledocTransform(serializedMobiledoc, siteUrl, transformFunction, null, options); +} + +export = mobiledocAbsoluteToRelative; diff --git a/packages/url-utils/lib/utils/mobiledoc-absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/mobiledoc-absolute-to-transform-ready.ts new file mode 100644 index 000000000..926f56ad8 --- /dev/null +++ b/packages/url-utils/lib/utils/mobiledoc-absolute-to-transform-ready.ts @@ -0,0 +1,22 @@ +import absoluteToTransformReady = require('./absolute-to-transform-ready'); +import mobiledocTransform = require('./mobiledoc-transform'); + +interface MobiledocAbsoluteToTransformReadyOptions { + assetsOnly?: boolean; + secure?: boolean; + cardTransformers?: any[]; +} + +function mobiledocAbsoluteToTransformReady(serializedMobiledoc: string, siteUrl: string, _options: MobiledocAbsoluteToTransformReadyOptions = {}): string { + const defaultOptions: MobiledocAbsoluteToTransformReadyOptions = {assetsOnly: false, secure: false, cardTransformers: []}; + const overrideOptions = {siteUrl, transformType: 'toTransformReady'}; + const options = Object.assign({}, defaultOptions, _options, overrideOptions); + + const transformFunction = function (_url: string, _siteUrl: string, _itemPath: string | null, __options: any): string { + return absoluteToTransformReady(_url, _siteUrl, __options); + }; + + return mobiledocTransform(serializedMobiledoc, siteUrl, transformFunction, null, options); +} + +export = mobiledocAbsoluteToTransformReady; diff --git a/packages/url-utils/lib/utils/mobiledoc-relative-to-absolute.ts b/packages/url-utils/lib/utils/mobiledoc-relative-to-absolute.ts new file mode 100644 index 000000000..c477f395e --- /dev/null +++ b/packages/url-utils/lib/utils/mobiledoc-relative-to-absolute.ts @@ -0,0 +1,18 @@ +import relativeToAbsolute = require('./relative-to-absolute'); +import mobiledocTransform = require('./mobiledoc-transform'); + +interface MobiledocRelativeToAbsoluteOptions { + assetsOnly?: boolean; + secure?: boolean; + cardTransformers?: any[]; +} + +function mobiledocRelativeToAbsolute(serializedMobiledoc: string, siteUrl: string, itemPath: string | null = null, _options: MobiledocRelativeToAbsoluteOptions = {}): string { + const defaultOptions: MobiledocRelativeToAbsoluteOptions = {assetsOnly: false, secure: false, cardTransformers: []}; + const overrideOptions = {siteUrl, itemPath, transformType: 'relativeToAbsolute'}; + const options = Object.assign({}, defaultOptions, _options, overrideOptions); + + return mobiledocTransform(serializedMobiledoc, siteUrl, relativeToAbsolute, itemPath, options); +} + +export = mobiledocRelativeToAbsolute; diff --git a/packages/url-utils/lib/utils/mobiledoc-relative-to-transform-ready.ts b/packages/url-utils/lib/utils/mobiledoc-relative-to-transform-ready.ts new file mode 100644 index 000000000..8dc117aea --- /dev/null +++ b/packages/url-utils/lib/utils/mobiledoc-relative-to-transform-ready.ts @@ -0,0 +1,18 @@ +import relativeToTransformReady = require('./relative-to-transform-ready'); +import mobiledocTransform = require('./mobiledoc-transform'); + +interface MobiledocRelativeToTransformReadyOptions { + assetsOnly?: boolean; + secure?: boolean; + cardTransformers?: any[]; +} + +function mobiledocRelativeToTransformReady(serializedMobiledoc: string, siteUrl: string, itemPath: string | null = null, _options: MobiledocRelativeToTransformReadyOptions = {}): string { + const defaultOptions: MobiledocRelativeToTransformReadyOptions = {assetsOnly: false, secure: false, cardTransformers: []}; + const overrideOptions = {siteUrl, transformType: 'toTransformReady'}; + const options = Object.assign({}, defaultOptions, _options, overrideOptions); + + return mobiledocTransform(serializedMobiledoc, siteUrl, relativeToTransformReady, itemPath, options); +} + +export = mobiledocRelativeToTransformReady; diff --git a/packages/url-utils/lib/utils/mobiledoc-to-transform-ready.ts b/packages/url-utils/lib/utils/mobiledoc-to-transform-ready.ts new file mode 100644 index 000000000..da8739066 --- /dev/null +++ b/packages/url-utils/lib/utils/mobiledoc-to-transform-ready.ts @@ -0,0 +1,24 @@ +import mobiledocRelativeToAbsolute = require('./mobiledoc-relative-to-absolute'); +import mobiledocAbsoluteToTransformReady = require('./mobiledoc-absolute-to-transform-ready'); + +interface MobiledocToTransformReadyOptions { + assetsOnly?: boolean; + secure?: boolean; + cardTransformers?: any[]; +} + +function mobiledocToTransformReady(mobiledoc: string, siteUrl: string, itemPath?: string | MobiledocToTransformReadyOptions | null, options?: MobiledocToTransformReadyOptions): string { + let actualItemPath: string | null = null; + let actualOptions: MobiledocToTransformReadyOptions | undefined = options; + + if (typeof itemPath === 'object' && itemPath !== null && !options) { + actualOptions = itemPath; + } else if (typeof itemPath === 'string') { + actualItemPath = itemPath; + } + + const absolute = mobiledocRelativeToAbsolute(mobiledoc, siteUrl, actualItemPath, actualOptions); + return mobiledocAbsoluteToTransformReady(absolute, siteUrl, actualOptions); +} + +export = mobiledocToTransformReady; diff --git a/packages/url-utils/lib/utils/mobiledoc-transform.ts b/packages/url-utils/lib/utils/mobiledoc-transform.ts new file mode 100644 index 000000000..690919178 --- /dev/null +++ b/packages/url-utils/lib/utils/mobiledoc-transform.ts @@ -0,0 +1,69 @@ +interface MobiledocTransformOptions { + assetsOnly?: boolean; + secure?: boolean; + cardTransformers?: Array<{ + name: string; + [key: string]: any; + }>; + transformType?: string; + siteUrl?: string; + itemPath?: string | null; +} + +type TransformFunction = (url: string, siteUrl: string, itemPath: string | null, options: MobiledocTransformOptions) => string; + +function mobiledocTransform(serializedMobiledoc: string, siteUrl: string, transformFunction: TransformFunction, itemPath: string | null, _options: MobiledocTransformOptions = {}): string { + const defaultOptions: MobiledocTransformOptions = {assetsOnly: false, secure: false, cardTransformers: []}; + const options = Object.assign({}, defaultOptions, _options, {siteUrl, itemPath}); + + // 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: Record = {}; + options.cardTransformers!.forEach((cardTransformer) => { + cardTransformers[cardTransformer.name] = cardTransformer[options.transformType!]; + }); + delete options.cardTransformers; + + // function only accepts serialized mobiledoc so there's no chance of accidentally + // modifying pass-by-reference objects + const mobiledoc: any = JSON.parse(serializedMobiledoc); + + // any mobiledoc links will have an 'a' markup with an 'href' attribute + (mobiledoc.markups || []).forEach((markup: any[]) => { + 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: any, index: number) => { + if (attr === 'href') { + hrefIndex = index + 1; + } + }); + + if (hrefIndex !== -1) { + const transformedUrl = transformFunction(markup[1][hrefIndex], siteUrl, itemPath, options); + if (transformedUrl) { + markup[1][hrefIndex] = transformedUrl; + } + } + } + }); + + // 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: any[]) => { + const [name, payload] = card; + if (cardTransformers[name]) { + // transformers take a payload and return a transformed payload + const transformedPayload = cardTransformers[name](payload, options); + card[1] = transformedPayload; + } + }); + + return JSON.stringify(mobiledoc); +} + +export = mobiledocTransform; From 3b66a3572aafaceb78cc15915b9c7248f6e73572 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Oct 2025 03:41:07 +0000 Subject: [PATCH 08/14] chore(url-utils): Convert plaintext transformation utilities to TypeScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Convert plaintext-to-transform-ready.js to TypeScript - Convert plaintext-relative-to-transform-ready.js to TypeScript - Convert plaintext-absolute-to-transform-ready.js to TypeScript Added proper type definitions and interfaces for plaintext URL transformations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../plaintext-absolute-to-transform-ready.ts | 34 +++++++++++++++++++ .../plaintext-relative-to-transform-ready.ts | 26 ++++++++++++++ .../lib/utils/plaintext-to-transform-ready.ts | 22 ++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 packages/url-utils/lib/utils/plaintext-absolute-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/plaintext-relative-to-transform-ready.ts create mode 100644 packages/url-utils/lib/utils/plaintext-to-transform-ready.ts diff --git a/packages/url-utils/lib/utils/plaintext-absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/plaintext-absolute-to-transform-ready.ts new file mode 100644 index 000000000..f17325d86 --- /dev/null +++ b/packages/url-utils/lib/utils/plaintext-absolute-to-transform-ready.ts @@ -0,0 +1,34 @@ +import {URL} from 'url'; +import absoluteToTransformReady = require('./absolute-to-transform-ready'); + +interface PlaintextAbsoluteToTransformReadyOptions { + replacementStr?: string; + withoutSubdirectory?: boolean; + assetsOnly?: boolean; + staticImageUrlPrefix?: string; +} + +function escapeRegExp(string: string): string { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} + +const plaintextAbsoluteToTransformReady = function plaintextAbsoluteToTransformReady(plaintext: string, rootUrl: string, itemPath?: string | PlaintextAbsoluteToTransformReadyOptions, options?: PlaintextAbsoluteToTransformReadyOptions): string { + // itemPath is optional, if it's an object may be the options param instead + if (typeof itemPath === 'object' && !options) { + options = itemPath; + itemPath = undefined; + } + + // plaintext links look like "Link title [url]" + // those links are all we care about so we can do a fast regex here + const rootURL = new URL(rootUrl); + const escapedRootUrl = escapeRegExp(`${rootURL.hostname}${rootURL.pathname.replace(/\/$/, '')}`); + const linkRegex = new RegExp(` \\[(https?://${escapedRootUrl}.*?)\\]`, 'g'); + + return plaintext.replace(linkRegex, function (fullMatch: string, url: string): string { + const newUrl = absoluteToTransformReady(`${url}`, rootUrl, options); + return ` [${newUrl}]`; + }); +}; + +export = plaintextAbsoluteToTransformReady; diff --git a/packages/url-utils/lib/utils/plaintext-relative-to-transform-ready.ts b/packages/url-utils/lib/utils/plaintext-relative-to-transform-ready.ts new file mode 100644 index 000000000..9d8fde710 --- /dev/null +++ b/packages/url-utils/lib/utils/plaintext-relative-to-transform-ready.ts @@ -0,0 +1,26 @@ +import {URL} from 'url'; +import relativeToTransformReady = require('./relative-to-transform-ready'); + +interface PlaintextRelativeToTransformReadyOptions { + replacementStr?: string; + staticImageUrlPrefix?: string; + assetsOnly?: boolean; + secure?: boolean; +} + +const plaintextRelativeToTransformReady = function plaintextRelativeToTransformReady(plaintext: string, rootUrl: string, itemPath?: string | PlaintextRelativeToTransformReadyOptions, options?: PlaintextRelativeToTransformReadyOptions): string { + // itemPath is optional, if it's an object may be the options param instead + if (typeof itemPath === 'object' && !options) { + options = itemPath; + itemPath = undefined; + } + + // 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: string, path: string): string { + const newPath = relativeToTransformReady(`${path}`, rootUrl, itemPath, options); + return ` [${newPath}]`; + }); +}; + +export = plaintextRelativeToTransformReady; diff --git a/packages/url-utils/lib/utils/plaintext-to-transform-ready.ts b/packages/url-utils/lib/utils/plaintext-to-transform-ready.ts new file mode 100644 index 000000000..e975145ff --- /dev/null +++ b/packages/url-utils/lib/utils/plaintext-to-transform-ready.ts @@ -0,0 +1,22 @@ +import {URL} from 'url'; +import plaintextRelativeToTransformReady = require('./plaintext-relative-to-transform-ready'); +import plaintextAbsoluteToTransformReady = require('./plaintext-absolute-to-transform-ready'); + +interface PlaintextToTransformReadyOptions { + replacementStr?: string; + staticImageUrlPrefix?: string; + assetsOnly?: boolean; + secure?: boolean; + withoutSubdirectory?: boolean; +} + +function plaintextToTransformReady(plaintext: string, siteUrl: string, itemPath?: string | PlaintextToTransformReadyOptions, options?: PlaintextToTransformReadyOptions): string { + if (typeof itemPath === 'object' && !options) { + options = itemPath; + itemPath = undefined; + } + const relativeTransformed = plaintextRelativeToTransformReady(plaintext, siteUrl, itemPath, options); + return plaintextAbsoluteToTransformReady(relativeTransformed, siteUrl, options); +} + +export = plaintextToTransformReady; From 84ecfb3a7349a4c59740cd380146a7520014473f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Oct 2025 03:41:34 +0000 Subject: [PATCH 09/14] chore(url-utils): Convert utils index to TypeScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Convert lib/utils/index.js to TypeScript - Import all utility functions with proper TypeScript syntax - Export all utilities as a single object 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- packages/url-utils/lib/utils/index.ts | 75 +++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 packages/url-utils/lib/utils/index.ts diff --git a/packages/url-utils/lib/utils/index.ts b/packages/url-utils/lib/utils/index.ts new file mode 100644 index 000000000..e93b1cdaa --- /dev/null +++ b/packages/url-utils/lib/utils/index.ts @@ -0,0 +1,75 @@ +import absoluteToRelative = require('./absolute-to-relative'); +import absoluteToTransformReady = require('./absolute-to-transform-ready'); +import deduplicateDoubleSlashes = require('./deduplicate-double-slashes'); +import deduplicateSubdirectory = require('./deduplicate-subdirectory'); +import htmlAbsoluteToRelative = require('./html-absolute-to-relative'); +import htmlRelativeToAbsolute = require('./html-relative-to-absolute'); +import htmlAbsoluteToTransformReady = require('./html-absolute-to-transform-ready'); +import htmlRelativeToTransformReady = require('./html-relative-to-transform-ready'); +import htmlToTransformReady = require('./html-to-transform-ready'); +import isSSL = require('./is-ssl'); +import markdownAbsoluteToRelative = require('./markdown-absolute-to-relative'); +import markdownRelativeToAbsolute = require('./markdown-relative-to-absolute'); +import markdownAbsoluteToTransformReady = require('./markdown-absolute-to-transform-ready'); +import markdownRelativeToTransformReady = require('./markdown-relative-to-transform-ready'); +import markdownToTransformReady = require('./markdown-to-transform-ready'); +import mobiledocAbsoluteToRelative = require('./mobiledoc-absolute-to-relative'); +import mobiledocRelativeToAbsolute = require('./mobiledoc-relative-to-absolute'); +import mobiledocAbsoluteToTransformReady = require('./mobiledoc-absolute-to-transform-ready'); +import mobiledocRelativeToTransformReady = require('./mobiledoc-relative-to-transform-ready'); +import mobiledocToTransformReady = require('./mobiledoc-to-transform-ready'); +import lexicalAbsoluteToRelative = require('./lexical-absolute-to-relative'); +import lexicalRelativeToAbsolute = require('./lexical-relative-to-absolute'); +import lexicalAbsoluteToTransformReady = require('./lexical-absolute-to-transform-ready'); +import lexicalRelativeToTransformReady = require('./lexical-relative-to-transform-ready'); +import lexicalToTransformReady = require('./lexical-to-transform-ready'); +import plaintextAbsoluteToTransformReady = require('./plaintext-absolute-to-transform-ready'); +import plaintextRelativeToTransformReady = require('./plaintext-relative-to-transform-ready'); +import plaintextToTransformReady = require('./plaintext-to-transform-ready'); +import relativeToAbsolute = require('./relative-to-absolute'); +import relativeToTransformReady = require('./relative-to-transform-ready'); +import replacePermalink = require('./replace-permalink'); +import stripSubdirectoryFromPath = require('./strip-subdirectory-from-path'); +import toTransformReady = require('./to-transform-ready'); +import transformReadyToAbsolute = require('./transform-ready-to-absolute'); +import transformReadyToRelative = require('./transform-ready-to-relative'); +import urlJoin = require('./url-join'); + +export = { + absoluteToRelative, + absoluteToTransformReady, + deduplicateDoubleSlashes, + deduplicateSubdirectory, + htmlAbsoluteToRelative, + htmlRelativeToAbsolute, + htmlAbsoluteToTransformReady, + htmlRelativeToTransformReady, + htmlToTransformReady, + isSSL, + markdownAbsoluteToRelative, + markdownRelativeToAbsolute, + markdownAbsoluteToTransformReady, + markdownRelativeToTransformReady, + markdownToTransformReady, + mobiledocAbsoluteToRelative, + mobiledocRelativeToAbsolute, + mobiledocAbsoluteToTransformReady, + mobiledocRelativeToTransformReady, + mobiledocToTransformReady, + lexicalAbsoluteToRelative, + lexicalRelativeToAbsolute, + lexicalAbsoluteToTransformReady, + lexicalRelativeToTransformReady, + lexicalToTransformReady, + plaintextAbsoluteToTransformReady, + plaintextRelativeToTransformReady, + plaintextToTransformReady, + relativeToAbsolute, + relativeToTransformReady, + replacePermalink, + stripSubdirectoryFromPath, + toTransformReady, + transformReadyToAbsolute, + transformReadyToRelative, + urlJoin +}; From 36f81dd0bf2d5bba79125c3f43ff0b0e778df43e Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Oct 2025 03:43:45 +0000 Subject: [PATCH 10/14] chore(url-utils): Convert main UrlUtils class and entry point to TypeScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Convert lib/UrlUtils.js to TypeScript with comprehensive type definitions - Add interfaces for UrlUtilsOptions, UrlUtilsConfig, TransformOptions, and UrlForData - Add proper method overloads for methods with optional itemPath parameter - Convert index.js to TypeScript - Maintain full backward compatibility with JavaScript API All public methods now have proper TypeScript signatures and type safety. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- packages/url-utils/index.ts | 3 + packages/url-utils/lib/UrlUtils.ts | 645 +++++++++++++++++++++++++++++ 2 files changed, 648 insertions(+) create mode 100644 packages/url-utils/index.ts create mode 100644 packages/url-utils/lib/UrlUtils.ts diff --git a/packages/url-utils/index.ts b/packages/url-utils/index.ts new file mode 100644 index 000000000..a608509de --- /dev/null +++ b/packages/url-utils/index.ts @@ -0,0 +1,3 @@ +import UrlUtils = require('./lib/UrlUtils'); + +export = UrlUtils; diff --git a/packages/url-utils/lib/UrlUtils.ts b/packages/url-utils/lib/UrlUtils.ts new file mode 100644 index 000000000..580c0ac21 --- /dev/null +++ b/packages/url-utils/lib/UrlUtils.ts @@ -0,0 +1,645 @@ +// Contains all path information to be used throughout the codebase. +import * as _ from 'lodash'; +import * as utils from './utils'; + +interface UrlUtilsConfig { + slugs: string[] | null; + redirectCacheMaxAge: number | null; + baseApiPath: string; + defaultApiType: 'content' | 'admin'; + staticImageUrlPrefix: string; + cardTransformers?: any[]; +} + +interface UrlUtilsOptions { + getSubdir: () => string; + getSiteUrl: () => string; + getAdminUrl?: () => string; + baseApiPath?: string; + defaultApiType?: 'content' | 'admin'; + slugs?: string[] | null; + redirectCacheMaxAge?: number | null; + staticImageUrlPrefix?: string; + cardTransformers?: any[]; +} + +interface UrlForData { + image?: string; + nav?: { + url: string; + }; + trailingSlash?: boolean; + type?: 'admin' | 'content'; +} + +interface TransformOptions { + assetsOnly?: boolean; + staticImageUrlPrefix?: string; + replacementStr?: string; + withoutSubdirectory?: boolean; + secure?: boolean; + ignoreProtocol?: boolean; + cardTransformers?: any[]; +} + +// similar to Object.assign but will not override defaults if a source value is undefined +function assignOptions(target: Record, ...sources: Record[]): Record { + const options = sources.map((x) => { + return Object.entries(x) + .filter(([, value]) => value !== undefined) + .reduce((obj, [key, value]) => (obj[key] = value, obj), {} as Record); + }); + return Object.assign(target, ...options); +} + +class UrlUtils { + private _config: UrlUtilsConfig; + public getSubdir: () => string; + public getSiteUrl: () => string; + public getAdminUrl?: () => string; + + /** + * Initialization method to pass in URL configurations + * @param {Object} options + * @param {Function} options.getSubdir + * @param {Function} options.getSiteUrl + * @param {Function} options.getAdminUrl Ghost instance admin URL + * @param {String} [options.baseApiPath='/ghost/api'] static prefix for serving API. Should not te passed in, unless the API is being run under custom URL + * @param {('content' | 'admin')} [options.defaultApiType='content'] default API type to be used + * @param {Object} [options.slugs] object with 2 properties reserved and protected containing arrays of special case slugs + * @param {Number} [options.redirectCacheMaxAge] + * @param {String} [options.staticImageUrlPrefix='content/images'] static prefix for serving images. Should not be passed in, unless customizing ghost instance image storage + */ + constructor(options: UrlUtilsOptions) { + const defaultOptions: Partial = { + slugs: null, + redirectCacheMaxAge: null, + baseApiPath: '/ghost/api', + defaultApiType: 'content', + staticImageUrlPrefix: 'content/images' + }; + + this._config = assignOptions({}, defaultOptions, options) as UrlUtilsConfig; + + this.getSubdir = options.getSubdir; + this.getSiteUrl = options.getSiteUrl; + this.getAdminUrl = options.getAdminUrl; + } + + getProtectedSlugs(): string[] | null { + let subDir = this.getSubdir(); + + if (!_.isEmpty(subDir)) { + return this._config.slugs!.concat([subDir.split('/').pop()!]); + } else { + return this._config.slugs; + } + } + + /** urlJoin + * Returns a URL/path for internal use in Ghost. + * @param {string} arguments takes arguments and concats those to a valid path/URL. + * @return {string} URL concatinated URL/path of arguments. + */ + urlJoin(...parts: string[]): string { + return utils.urlJoin(parts, {rootUrl: this.getSiteUrl()}); + } + + // ## createUrl + // Simple url creation from a given path + // Ensures that our urls contain the subdirectory if there is one + // And are correctly formatted as either relative or absolute + // Usage: + // createUrl('/', true) -> http://my-ghost-blog.com/ + // E.g. /blog/ subdir + // createUrl('/welcome-to-ghost/') -> /blog/welcome-to-ghost/ + // Parameters: + // - urlPath - string which must start and end with a slash + // - 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?: boolean): string { + let base: string; + + // create base of url, always ends without a slash + if (absolute) { + base = this.getSiteUrl(); + } else { + base = this.getSubdir(); + } + + if (trailingSlash) { + if (!urlPath.match(/\/$/)) { + urlPath += '/'; + } + } + + return this.urlJoin(base, urlPath); + } + + // ## urlFor + // Synchronous url creation for a given context + // Can generate a url for a named path and given path. + // Determines what sort of context it has been given, and delegates to the correct generation method, + // Finally passing to createUrl, to ensure any subdirectory is honoured, and the url is absolute if needed + // Usage: + // urlFor('home', true) -> http://my-ghost-blog.com/ + // E.g. /blog/ subdir + // urlFor({relativeUrl: '/my-static-page/'}) -> /blog/my-static-page/ + // Parameters: + // - context - a string, or json object describing the context for which you need a url + // - data (optional) - a json object containing data needed to generate a url + // - 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: string | {relativeUrl: string}, data?: UrlForData | boolean, absolute?: boolean): string { + let urlPath = '/'; + let imagePathRe: RegExp; + let knownObjects = ['image', 'nav']; + let baseUrl: string; + let hostname: string; + + // this will become really big + let knownPaths: Record = { + home: '/', + sitemap_xsl: '/sitemap.xsl' + }; + + // Make data properly optional + if (_.isBoolean(data)) { + absolute = data; + data = undefined; + } + + if (_.isObject(context) && (context as {relativeUrl: string}).relativeUrl) { + urlPath = (context as {relativeUrl: string}).relativeUrl; + } else if (_.isString(context) && _.indexOf(knownObjects, context) !== -1) { + if (context === 'image' && (data as UrlForData)?.image) { + urlPath = (data as UrlForData).image!; + imagePathRe = new RegExp('^' + this.getSubdir() + '/' + this._config.staticImageUrlPrefix); + absolute = imagePathRe.test((data as UrlForData).image!) ? absolute : false; + + if (absolute) { + // Remove the sub-directory from the URL because ghostConfig will add it back. + urlPath = urlPath.replace(new RegExp('^' + this.getSubdir()), ''); + baseUrl = this.getSiteUrl().replace(/\/$/, ''); + urlPath = baseUrl + urlPath; + } + + return urlPath; + } else if (context === 'nav' && (data as UrlForData)?.nav) { + urlPath = (data as UrlForData).nav!.url; + baseUrl = this.getSiteUrl(); + hostname = baseUrl.split('//')[1]; + + // If the hostname is present in the url + if (urlPath.indexOf(hostname) > -1 + // do no not apply, if there is a subdomain, or a mailto link + && !urlPath.split(hostname)[0].match(/\.|mailto:/) + // do not apply, if there is a port after the hostname + && urlPath.split(hostname)[1].substring(0, 1) !== ':') { + // make link relative to account for possible mismatch in http/https etc, force absolute + urlPath = urlPath.split(hostname)[1]; + urlPath = this.urlJoin('/', urlPath); + absolute = true; + } + } + } else if (context === 'home' && absolute) { + urlPath = this.getSiteUrl(); + + // 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 as UrlForData)?.trailingSlash === false) { + urlPath = urlPath.replace(/\/$/, ''); + } + } else if (context === 'admin') { + let adminUrl = this.getAdminUrl ? this.getAdminUrl() : this.getSiteUrl(); + let adminPath = '/ghost/'; + + if (absolute) { + urlPath = this.urlJoin(adminUrl, adminPath); + } else { + urlPath = adminPath; + } + } else if (context === 'api') { + let adminUrl = this.getAdminUrl ? this.getAdminUrl() : this.getSiteUrl(); + let apiPath = this._config.baseApiPath + '/'; + + if ((data as UrlForData)?.type && ['admin', 'content'].includes((data as UrlForData).type!)) { + apiPath += (data as UrlForData).type; + } else { + apiPath += this._config.defaultApiType; + } + + // Ensure we end with a trailing slash + apiPath += '/'; + + if (absolute) { + urlPath = this.urlJoin(adminUrl, apiPath); + } else { + urlPath = apiPath; + } + } else if (_.isString(context) && _.indexOf(_.keys(knownPaths), context) !== -1) { + // trying to create a url for a named path + urlPath = knownPaths[context]; + } + + // This url already has a protocol so is likely an external url to be returned + // or it is an alternative scheme, protocol-less, or an anchor-only path + if (urlPath && (urlPath.indexOf('://') !== -1 || urlPath.match(/^(\/\/|#|[a-zA-Z0-9-]+:)/))) { + return urlPath; + } + + return this.createUrl(urlPath, absolute); + } + + redirect301(res: any, redirectUrl: string): any { + res.set({'Cache-Control': 'public, max-age=' + this._config.redirectCacheMaxAge}); + return res.redirect(301, redirectUrl); + } + + redirectToAdmin(status: number, res: any, adminPath: string): any { + let redirectUrl = this.urlJoin(this.urlFor('admin', true), adminPath, '/'); + + if (status === 301) { + return this.redirect301(res, redirectUrl); + } + return res.redirect(redirectUrl); + } + + absoluteToRelative(url: string, options?: TransformOptions): string { + return utils.absoluteToRelative(url, this.getSiteUrl(), options); + } + + relativeToAbsolute(url: string, options?: TransformOptions): string; + relativeToAbsolute(url: string, itemPath: string | null, options?: TransformOptions): string; + relativeToAbsolute(url: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + return utils.relativeToAbsolute(url, this.getSiteUrl(), itemPathOrOptions, options); + } + return utils.relativeToAbsolute(url, this.getSiteUrl(), itemPathOrOptions, options); + } + + toTransformReady(url: string, options?: TransformOptions): string; + toTransformReady(url: string, itemPath: string | null, options?: TransformOptions): string; + toTransformReady(url: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + return utils.toTransformReady(url, this.getSiteUrl(), itemPathOrOptions, options); + } + return utils.toTransformReady(url, this.getSiteUrl(), itemPathOrOptions, options); + } + + absoluteToTransformReady(url: string, options?: TransformOptions): string { + return utils.absoluteToTransformReady(url, this.getSiteUrl(), options); + } + + relativeToTransformReady(url: string, options?: TransformOptions): string; + relativeToTransformReady(url: string, itemPath: string | null, options?: TransformOptions): string; + relativeToTransformReady(url: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + return utils.relativeToTransformReady(url, this.getSiteUrl(), itemPathOrOptions, options); + } + return utils.relativeToTransformReady(url, this.getSiteUrl(), itemPathOrOptions, options); + } + + transformReadyToAbsolute(url: string, options?: TransformOptions): string { + return utils.transformReadyToAbsolute(url, this.getSiteUrl(), options); + } + + transformReadyToRelative(url: string, options?: TransformOptions): string { + return utils.transformReadyToRelative(url, this.getSiteUrl(), options); + } + + htmlToTransformReady(html: string, options?: TransformOptions): string; + htmlToTransformReady(html: string, itemPath: string | null, options?: TransformOptions): string; + htmlToTransformReady(html: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + return utils.htmlToTransformReady(html, this.getSiteUrl(), itemPathOrOptions, options); + } + return utils.htmlToTransformReady(html, this.getSiteUrl(), itemPathOrOptions, options); + } + + /** + * Convert relative URLs in html into absolute URLs + * @param {string} html + * @param {string} itemPath (path of current context) + * @param {Object} options + * @returns {object} htmlContent + * @description Takes html, blog url and item path and converts relative url into + * 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: string, options?: TransformOptions): string; + htmlRelativeToAbsolute(html: string, itemPath: string | null, options?: TransformOptions): string; + htmlRelativeToAbsolute(html: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix + }; + + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); + return utils.htmlRelativeToAbsolute(html, this.getSiteUrl(), null, _options); + } + + const _options = assignOptions({}, defaultOptions, options || {}); + return utils.htmlRelativeToAbsolute(html, this.getSiteUrl(), itemPathOrOptions, _options); + } + + htmlRelativeToTransformReady(html: string, options?: TransformOptions): string; + htmlRelativeToTransformReady(html: string, itemPath: string | null, options?: TransformOptions): string; + htmlRelativeToTransformReady(html: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix + }; + + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); + return utils.htmlRelativeToTransformReady(html, this.getSiteUrl(), null, _options); + } + + const _options = assignOptions({}, defaultOptions, options || {}); + return utils.htmlRelativeToTransformReady(html, this.getSiteUrl(), itemPathOrOptions, _options); + } + + htmlAbsoluteToRelative(html: string, options: TransformOptions = {}): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix + }; + const _options = assignOptions({}, defaultOptions, options); + return utils.htmlAbsoluteToRelative(html, this.getSiteUrl(), _options); + } + + htmlAbsoluteToTransformReady(html: string, options: TransformOptions = {}): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix + }; + const _options = assignOptions({}, defaultOptions, options); + return utils.htmlAbsoluteToTransformReady(html, this.getSiteUrl(), _options); + } + + markdownToTransformReady(markdown: string, options?: TransformOptions): string; + markdownToTransformReady(markdown: string, itemPath: string | null, options?: TransformOptions): string; + markdownToTransformReady(markdown: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + return utils.markdownToTransformReady(markdown, this.getSiteUrl(), itemPathOrOptions, options); + } + return utils.markdownToTransformReady(markdown, this.getSiteUrl(), itemPathOrOptions, options); + } + + markdownRelativeToAbsolute(markdown: string, options?: TransformOptions): string; + markdownRelativeToAbsolute(markdown: string, itemPath: string | null, options?: TransformOptions): string; + markdownRelativeToAbsolute(markdown: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix + }; + + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); + return utils.markdownRelativeToAbsolute(markdown, this.getSiteUrl(), null, _options); + } + + const _options = assignOptions({}, defaultOptions, options || {}); + return utils.markdownRelativeToAbsolute(markdown, this.getSiteUrl(), itemPathOrOptions, _options); + } + + markdownRelativeToTransformReady(markdown: string, options?: TransformOptions): string; + markdownRelativeToTransformReady(markdown: string, itemPath: string | null, options?: TransformOptions): string; + markdownRelativeToTransformReady(markdown: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix + }; + + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); + return utils.markdownRelativeToTransformReady(markdown, this.getSiteUrl(), null, _options); + } + + const _options = assignOptions({}, defaultOptions, options || {}); + return utils.markdownRelativeToTransformReady(markdown, this.getSiteUrl(), itemPathOrOptions, _options); + } + + markdownAbsoluteToRelative(markdown: string, options: TransformOptions = {}): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix + }; + const _options = assignOptions({}, defaultOptions, options); + return utils.markdownAbsoluteToRelative(markdown, this.getSiteUrl(), _options); + } + + markdownAbsoluteToTransformReady(markdown: string, options?: TransformOptions): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix + }; + const _options = assignOptions({}, defaultOptions, options); + return utils.markdownAbsoluteToTransformReady(markdown, this.getSiteUrl(), _options); + } + + mobiledocToTransformReady(serializedMobiledoc: string, options?: TransformOptions): string; + mobiledocToTransformReady(serializedMobiledoc: string, itemPath: string | null, options?: TransformOptions): string; + mobiledocToTransformReady(serializedMobiledoc: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + const defaultOptions: TransformOptions = { + cardTransformers: this._config.cardTransformers + }; + + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); + return utils.mobiledocToTransformReady(serializedMobiledoc, this.getSiteUrl(), null, _options); + } + + const _options = assignOptions({}, defaultOptions, options || {}); + return utils.mobiledocToTransformReady(serializedMobiledoc, this.getSiteUrl(), itemPathOrOptions, _options); + } + + mobiledocRelativeToAbsolute(serializedMobiledoc: string, options?: TransformOptions): string; + mobiledocRelativeToAbsolute(serializedMobiledoc: string, itemPath: string | null, options?: TransformOptions): string; + mobiledocRelativeToAbsolute(serializedMobiledoc: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix, + cardTransformers: this._config.cardTransformers + }; + + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); + return utils.mobiledocRelativeToAbsolute(serializedMobiledoc, this.getSiteUrl(), null, _options); + } + + const _options = assignOptions({}, defaultOptions, options || {}); + return utils.mobiledocRelativeToAbsolute(serializedMobiledoc, this.getSiteUrl(), itemPathOrOptions, _options); + } + + mobiledocRelativeToTransformReady(serializedMobiledoc: string, options?: TransformOptions): string; + mobiledocRelativeToTransformReady(serializedMobiledoc: string, itemPath: string | null, options?: TransformOptions): string; + mobiledocRelativeToTransformReady(serializedMobiledoc: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix, + cardTransformers: this._config.cardTransformers + }; + + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); + return utils.mobiledocRelativeToTransformReady(serializedMobiledoc, this.getSiteUrl(), null, _options); + } + + const _options = assignOptions({}, defaultOptions, options || {}); + return utils.mobiledocRelativeToTransformReady(serializedMobiledoc, this.getSiteUrl(), itemPathOrOptions, _options); + } + + mobiledocAbsoluteToRelative(serializedMobiledoc: string, options: TransformOptions = {}): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix, + cardTransformers: this._config.cardTransformers + }; + const _options = assignOptions({}, defaultOptions, options); + return utils.mobiledocAbsoluteToRelative(serializedMobiledoc, this.getSiteUrl(), _options); + } + + mobiledocAbsoluteToTransformReady(serializedMobiledoc: string, options: TransformOptions = {}): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix, + cardTransformers: this._config.cardTransformers + }; + const _options = assignOptions({}, defaultOptions, options); + return utils.mobiledocAbsoluteToTransformReady(serializedMobiledoc, this.getSiteUrl(), _options); + } + + lexicalToTransformReady(serializedLexical: string, options?: TransformOptions): string; + lexicalToTransformReady(serializedLexical: string, itemPath: string | null, options?: TransformOptions): string; + lexicalToTransformReady(serializedLexical: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + const defaultOptions: TransformOptions = { + cardTransformers: this._config.cardTransformers + }; + + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); + return utils.lexicalToTransformReady(serializedLexical, this.getSiteUrl(), null, _options); + } + + const _options = assignOptions({}, defaultOptions, options || {}); + return utils.lexicalToTransformReady(serializedLexical, this.getSiteUrl(), itemPathOrOptions, _options); + } + + lexicalRelativeToAbsolute(serializedLexical: string, options?: TransformOptions): string; + lexicalRelativeToAbsolute(serializedLexical: string, itemPath: string | null, options?: TransformOptions): string; + lexicalRelativeToAbsolute(serializedLexical: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix, + cardTransformers: this._config.cardTransformers + }; + + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); + return utils.lexicalRelativeToAbsolute(serializedLexical, this.getSiteUrl(), null, _options); + } + + const _options = assignOptions({}, defaultOptions, options || {}); + return utils.lexicalRelativeToAbsolute(serializedLexical, this.getSiteUrl(), itemPathOrOptions, _options); + } + + lexicalRelativeToTransformReady(serializedLexical: string, options?: TransformOptions): string; + lexicalRelativeToTransformReady(serializedLexical: string, itemPath: string | null, options?: TransformOptions): string; + lexicalRelativeToTransformReady(serializedLexical: string, itemPathOrOptions?: string | TransformOptions | null, options?: TransformOptions): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix, + cardTransformers: this._config.cardTransformers + }; + + if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { + const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); + return utils.lexicalRelativeToTransformReady(serializedLexical, this.getSiteUrl(), null, _options); + } + + const _options = assignOptions({}, defaultOptions, options || {}); + return utils.lexicalRelativeToTransformReady(serializedLexical, this.getSiteUrl(), itemPathOrOptions, _options); + } + + lexicalAbsoluteToRelative(serializedLexical: string, options: TransformOptions = {}): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix, + cardTransformers: this._config.cardTransformers + }; + const _options = assignOptions({}, defaultOptions, options); + return utils.lexicalAbsoluteToRelative(serializedLexical, this.getSiteUrl(), _options); + } + + lexicalAbsoluteToTransformReady(serializedLexical: string, options: TransformOptions = {}): string { + const defaultOptions: TransformOptions = { + assetsOnly: false, + staticImageUrlPrefix: this._config.staticImageUrlPrefix, + cardTransformers: this._config.cardTransformers + }; + const _options = assignOptions({}, defaultOptions, options); + return utils.lexicalAbsoluteToTransformReady(serializedLexical, this.getSiteUrl(), _options); + } + + plaintextToTransformReady(plaintext: string, options: TransformOptions = {}): string { + const defaultOptions: TransformOptions = { + staticImageUrlPrefix: this._config.staticImageUrlPrefix + }; + const _options = assignOptions({}, defaultOptions, options); + return utils.plaintextToTransformReady(plaintext, this.getSiteUrl(), _options); + } + + /** + * Return whether the provided URL is part of the site (checks if same domain and within subdirectory) + * @param {URL} url + * @param {string} [context] describing the context for which you need to check a url + * @returns {boolean} + */ + isSiteUrl(url: URL, context = 'home'): boolean { + const siteUrl = new URL(this.urlFor(context, true)); + if (siteUrl.host === url.host) { + if (url.pathname.startsWith(siteUrl.pathname)) { + return true; + } + return false; + } + return false; + } + + get isSSL() { + return utils.isSSL; + } + + get replacePermalink() { + return utils.replacePermalink; + } + + get deduplicateDoubleSlashes() { + return utils.deduplicateDoubleSlashes; + } + + /** + * If you request **any** image in Ghost, it get's served via + * http://your-blog.com/content/images/2017/01/02/author.png + * + * /content/images/ is a static prefix for serving images! + * + * 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(): string { + return this._config.staticImageUrlPrefix; + } + + // expose underlying functions to ease testing + get _utils() { + return utils; + } +} + +export = UrlUtils; From 06366e335747a59f28ec11d6194af7f4c53a8dbb Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Oct 2025 03:58:24 +0000 Subject: [PATCH 11/14] fix(url-utils): Fix TypeScript compilation errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix module imports in UrlUtils.ts to use CommonJS require - Export all option interfaces to allow type naming in declarations - Fix type narrowing issues in functions with overloaded parameters - Add explicit return type to _utils getter - Convert some exports from export= to export default for compatibility - Fix null/undefined handling in optional parameters All TypeScript compilation errors resolved, build succeeds. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- packages/url-utils/lib/UrlUtils.ts | 16 +++++++------- .../lib/utils/absolute-to-relative.ts | 6 +++--- .../lib/utils/absolute-to-transform-ready.ts | 8 +++---- .../lib/utils/html-absolute-to-relative.ts | 2 +- .../utils/html-absolute-to-transform-ready.ts | 8 +++---- .../lib/utils/html-relative-to-absolute.ts | 2 +- .../utils/html-relative-to-transform-ready.ts | 15 ++++++------- .../lib/utils/html-to-transform-ready.ts | 9 ++++---- packages/url-utils/lib/utils/index.ts | 20 +++++++++--------- .../lib/utils/lexical-absolute-to-relative.ts | 2 +- .../lexical-absolute-to-transform-ready.ts | 2 +- .../lib/utils/lexical-relative-to-absolute.ts | 2 +- .../lexical-relative-to-transform-ready.ts | 2 +- .../lib/utils/lexical-to-transform-ready.ts | 7 ++++--- .../utils/markdown-absolute-to-relative.ts | 2 +- .../markdown-absolute-to-transform-ready.ts | 4 ++-- .../utils/markdown-relative-to-absolute.ts | 2 +- .../markdown-relative-to-transform-ready.ts | 4 ++-- .../lib/utils/markdown-to-transform-ready.ts | 7 ++++--- .../utils/mobiledoc-absolute-to-relative.ts | 2 +- .../mobiledoc-absolute-to-transform-ready.ts | 2 +- .../utils/mobiledoc-relative-to-absolute.ts | 2 +- .../mobiledoc-relative-to-transform-ready.ts | 2 +- .../plaintext-absolute-to-transform-ready.ts | 8 +++---- .../plaintext-relative-to-transform-ready.ts | 8 +++---- .../lib/utils/plaintext-to-transform-ready.ts | 4 ++-- .../lib/utils/relative-to-absolute.ts | 21 ++++++++++--------- .../lib/utils/relative-to-transform-ready.ts | 15 ++++++------- .../url-utils/lib/utils/to-transform-ready.ts | 11 +++++----- .../lib/utils/transform-ready-to-absolute.ts | 6 +++--- .../lib/utils/transform-ready-to-relative.ts | 6 +++--- yarn.lock | 21 ++++++++++++++++++- 32 files changed, 127 insertions(+), 101 deletions(-) diff --git a/packages/url-utils/lib/UrlUtils.ts b/packages/url-utils/lib/UrlUtils.ts index 580c0ac21..a6becce7a 100644 --- a/packages/url-utils/lib/UrlUtils.ts +++ b/packages/url-utils/lib/UrlUtils.ts @@ -1,6 +1,6 @@ // Contains all path information to be used throughout the codebase. import * as _ from 'lodash'; -import * as utils from './utils'; +const utils = require('./utils'); interface UrlUtilsConfig { slugs: string[] | null; @@ -339,7 +339,7 @@ class UrlUtils { if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); - return utils.htmlRelativeToAbsolute(html, this.getSiteUrl(), null, _options); + return utils.htmlRelativeToAbsolute(html, this.getSiteUrl(), itemPathOrOptions as string | null, _options); } const _options = assignOptions({}, defaultOptions, options || {}); @@ -400,7 +400,7 @@ class UrlUtils { if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); - return utils.markdownRelativeToAbsolute(markdown, this.getSiteUrl(), null, _options); + return utils.markdownRelativeToAbsolute(markdown, this.getSiteUrl(), itemPathOrOptions as string | null, _options); } const _options = assignOptions({}, defaultOptions, options || {}); @@ -417,7 +417,7 @@ class UrlUtils { if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); - return utils.markdownRelativeToTransformReady(markdown, this.getSiteUrl(), null, _options); + return utils.markdownRelativeToTransformReady(markdown, this.getSiteUrl(), itemPathOrOptions as string | null, _options); } const _options = assignOptions({}, defaultOptions, options || {}); @@ -433,7 +433,7 @@ class UrlUtils { return utils.markdownAbsoluteToRelative(markdown, this.getSiteUrl(), _options); } - markdownAbsoluteToTransformReady(markdown: string, options?: TransformOptions): string { + markdownAbsoluteToTransformReady(markdown: string, options: TransformOptions = {}): string { const defaultOptions: TransformOptions = { assetsOnly: false, staticImageUrlPrefix: this._config.staticImageUrlPrefix @@ -541,7 +541,7 @@ class UrlUtils { if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); - return utils.lexicalRelativeToAbsolute(serializedLexical, this.getSiteUrl(), null, _options); + return utils.lexicalRelativeToAbsolute(serializedLexical, this.getSiteUrl(), itemPathOrOptions as string | null, _options); } const _options = assignOptions({}, defaultOptions, options || {}); @@ -559,7 +559,7 @@ class UrlUtils { if (typeof itemPathOrOptions === 'object' || itemPathOrOptions === null) { const _options = assignOptions({}, defaultOptions, itemPathOrOptions || {}); - return utils.lexicalRelativeToTransformReady(serializedLexical, this.getSiteUrl(), null, _options); + return utils.lexicalRelativeToTransformReady(serializedLexical, this.getSiteUrl(), itemPathOrOptions as string | null, _options); } const _options = assignOptions({}, defaultOptions, options || {}); @@ -637,7 +637,7 @@ class UrlUtils { } // expose underlying functions to ease testing - get _utils() { + get _utils(): any { return utils; } } diff --git a/packages/url-utils/lib/utils/absolute-to-relative.ts b/packages/url-utils/lib/utils/absolute-to-relative.ts index ca170ef09..311f85f2d 100644 --- a/packages/url-utils/lib/utils/absolute-to-relative.ts +++ b/packages/url-utils/lib/utils/absolute-to-relative.ts @@ -2,7 +2,7 @@ import {URL} from 'url'; import stripSubdirectoryFromPath = require('./strip-subdirectory-from-path'); -interface AbsoluteToRelativeOptions { +export interface AbsoluteToRelativeOptions { ignoreProtocol?: boolean; withoutSubdirectory?: boolean; assetsOnly?: boolean; @@ -19,7 +19,7 @@ interface AbsoluteToRelativeOptions { * @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: string, rootUrl: string, _options: AbsoluteToRelativeOptions = {}): string { +export const absoluteToRelative = function absoluteToRelative(url: string, rootUrl: string, _options: AbsoluteToRelativeOptions = {}): string { const defaultOptions: AbsoluteToRelativeOptions = { ignoreProtocol: true, withoutSubdirectory: false, @@ -67,4 +67,4 @@ const absoluteToRelative = function absoluteToRelative(url: string, rootUrl: str return url; }; -export = absoluteToRelative; +export default absoluteToRelative; diff --git a/packages/url-utils/lib/utils/absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/absolute-to-transform-ready.ts index 9d2ef83f5..5cc66485d 100644 --- a/packages/url-utils/lib/utils/absolute-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/absolute-to-transform-ready.ts @@ -1,14 +1,14 @@ import {URL} from 'url'; -import absoluteToRelative = require('./absolute-to-relative'); +import absoluteToRelative from './absolute-to-relative'; -interface AbsoluteToTransformReadyOptions { +export interface AbsoluteToTransformReadyOptions { replacementStr?: string; withoutSubdirectory?: boolean; assetsOnly?: boolean; staticImageUrlPrefix?: string; } -const absoluteToTransformReady = function (url: string, root: string, _options?: AbsoluteToTransformReadyOptions): string { +export const absoluteToTransformReady = function (url: string, root: string, _options?: AbsoluteToTransformReadyOptions): string { const defaultOptions: AbsoluteToTransformReadyOptions = { replacementStr: '__GHOST_URL__', withoutSubdirectory: true @@ -44,4 +44,4 @@ const absoluteToTransformReady = function (url: string, root: string, _options?: return `${options.replacementStr}${relativeUrl}`; }; -export = absoluteToTransformReady; +export default absoluteToTransformReady; diff --git a/packages/url-utils/lib/utils/html-absolute-to-relative.ts b/packages/url-utils/lib/utils/html-absolute-to-relative.ts index 23e0c89b4..e4d47de0a 100644 --- a/packages/url-utils/lib/utils/html-absolute-to-relative.ts +++ b/packages/url-utils/lib/utils/html-absolute-to-relative.ts @@ -1,5 +1,5 @@ import htmlTransform = require('./html-transform'); -import absoluteToRelative = require('./absolute-to-relative'); +import absoluteToRelative from './absolute-to-relative'; interface HtmlAbsoluteToRelativeOptions { assetsOnly?: boolean; diff --git a/packages/url-utils/lib/utils/html-absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/html-absolute-to-transform-ready.ts index 9d0b8b7a9..3f8982e12 100644 --- a/packages/url-utils/lib/utils/html-absolute-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/html-absolute-to-transform-ready.ts @@ -1,14 +1,14 @@ import htmlTransform = require('./html-transform'); -import absoluteToTransformReady = require('./absolute-to-transform-ready'); +import absoluteToTransformReady from './absolute-to-transform-ready'; -interface HtmlAbsoluteToTransformReadyOptions { +export interface HtmlAbsoluteToTransformReadyOptions { assetsOnly?: boolean; ignoreProtocol?: boolean; staticImageUrlPrefix?: string; earlyExitMatchStr?: string; } -const htmlAbsoluteToTransformReady = function (html = '', siteUrl: string, _options?: HtmlAbsoluteToTransformReadyOptions): string { +export const htmlAbsoluteToTransformReady = function (html = '', siteUrl: string, _options?: HtmlAbsoluteToTransformReadyOptions): string { const defaultOptions: HtmlAbsoluteToTransformReadyOptions = {assetsOnly: false, ignoreProtocol: true}; const options = Object.assign({}, defaultOptions, _options || {}); @@ -24,4 +24,4 @@ const htmlAbsoluteToTransformReady = function (html = '', siteUrl: string, _opti return htmlTransform(html, siteUrl, transformFunction, '', options); }; -export = htmlAbsoluteToTransformReady; +export default htmlAbsoluteToTransformReady; diff --git a/packages/url-utils/lib/utils/html-relative-to-absolute.ts b/packages/url-utils/lib/utils/html-relative-to-absolute.ts index 087b52f0d..764a339f5 100644 --- a/packages/url-utils/lib/utils/html-relative-to-absolute.ts +++ b/packages/url-utils/lib/utils/html-relative-to-absolute.ts @@ -1,5 +1,5 @@ import htmlTransform = require('./html-transform'); -import relativeToAbsolute = require('./relative-to-absolute'); +import relativeToAbsolute from './relative-to-absolute'; interface HtmlRelativeToAbsoluteOptions { assetsOnly?: boolean; diff --git a/packages/url-utils/lib/utils/html-relative-to-transform-ready.ts b/packages/url-utils/lib/utils/html-relative-to-transform-ready.ts index 70b1d87e6..edf51c9ee 100644 --- a/packages/url-utils/lib/utils/html-relative-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/html-relative-to-transform-ready.ts @@ -1,7 +1,7 @@ import htmlTransform = require('./html-transform'); -import relativeToTransformReady = require('./relative-to-transform-ready'); +import relativeToTransformReady from './relative-to-transform-ready'; -interface HtmlRelativeToTransformReadyOptions { +export interface HtmlRelativeToTransformReadyOptions { replacementStr?: string; assetsOnly?: boolean; staticImageUrlPrefix?: string; @@ -9,11 +9,12 @@ interface HtmlRelativeToTransformReadyOptions { earlyExitMatchStr?: string; } -const htmlRelativeToTransformReady = function (html = '', root: string, itemPath?: string | HtmlRelativeToTransformReadyOptions | null, _options?: HtmlRelativeToTransformReadyOptions): string { +export const htmlRelativeToTransformReady = function (html = '', root: string, itemPath?: string | HtmlRelativeToTransformReadyOptions | null, _options?: HtmlRelativeToTransformReadyOptions): string { // itemPath is optional, if it's an object may be the options param instead + let actualItemPath: string | null | undefined = itemPath as string | null | undefined; if (typeof itemPath === 'object' && !_options) { - _options = itemPath; - itemPath = null; + _options = itemPath as HtmlRelativeToTransformReadyOptions; + actualItemPath = null; } const defaultOptions: HtmlRelativeToTransformReadyOptions = { @@ -30,7 +31,7 @@ const htmlRelativeToTransformReady = function (html = '', root: string, itemPath options.earlyExitMatchStr = options.staticImageUrlPrefix; } - return htmlTransform(html, root, relativeToTransformReady, itemPath as string | null, options); + return htmlTransform(html, root, relativeToTransformReady, actualItemPath as string | null, options); }; -export = htmlRelativeToTransformReady; +export default htmlRelativeToTransformReady; diff --git a/packages/url-utils/lib/utils/html-to-transform-ready.ts b/packages/url-utils/lib/utils/html-to-transform-ready.ts index 049397cf3..2088b5ea5 100644 --- a/packages/url-utils/lib/utils/html-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/html-to-transform-ready.ts @@ -1,5 +1,5 @@ import htmlRelativeToAbsolute = require('./html-relative-to-absolute'); -import htmlAbsoluteToTransformReady = require('./html-absolute-to-transform-ready'); +import htmlAbsoluteToTransformReady from './html-absolute-to-transform-ready'; interface HtmlToTransformReadyOptions { assetsOnly?: boolean; @@ -8,11 +8,12 @@ interface HtmlToTransformReadyOptions { } function htmlToTransformReady(html: string, siteUrl: string, itemPath?: string | HtmlToTransformReadyOptions | null, options?: HtmlToTransformReadyOptions): string { + let actualItemPath: string | null | undefined = itemPath as string | null | undefined; if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + options = itemPath as HtmlToTransformReadyOptions; + actualItemPath = null; } - const absolute = htmlRelativeToAbsolute(html, siteUrl, itemPath || null, options); + const absolute = htmlRelativeToAbsolute(html, siteUrl, actualItemPath || null, options); return htmlAbsoluteToTransformReady(absolute, siteUrl, options); } diff --git a/packages/url-utils/lib/utils/index.ts b/packages/url-utils/lib/utils/index.ts index e93b1cdaa..1f3243c3d 100644 --- a/packages/url-utils/lib/utils/index.ts +++ b/packages/url-utils/lib/utils/index.ts @@ -1,11 +1,11 @@ -import absoluteToRelative = require('./absolute-to-relative'); -import absoluteToTransformReady = require('./absolute-to-transform-ready'); +import absoluteToRelative from './absolute-to-relative'; +import absoluteToTransformReady from './absolute-to-transform-ready'; import deduplicateDoubleSlashes = require('./deduplicate-double-slashes'); import deduplicateSubdirectory = require('./deduplicate-subdirectory'); import htmlAbsoluteToRelative = require('./html-absolute-to-relative'); import htmlRelativeToAbsolute = require('./html-relative-to-absolute'); -import htmlAbsoluteToTransformReady = require('./html-absolute-to-transform-ready'); -import htmlRelativeToTransformReady = require('./html-relative-to-transform-ready'); +import htmlAbsoluteToTransformReady from './html-absolute-to-transform-ready'; +import htmlRelativeToTransformReady from './html-relative-to-transform-ready'; import htmlToTransformReady = require('./html-to-transform-ready'); import isSSL = require('./is-ssl'); import markdownAbsoluteToRelative = require('./markdown-absolute-to-relative'); @@ -23,16 +23,16 @@ import lexicalRelativeToAbsolute = require('./lexical-relative-to-absolute'); import lexicalAbsoluteToTransformReady = require('./lexical-absolute-to-transform-ready'); import lexicalRelativeToTransformReady = require('./lexical-relative-to-transform-ready'); import lexicalToTransformReady = require('./lexical-to-transform-ready'); -import plaintextAbsoluteToTransformReady = require('./plaintext-absolute-to-transform-ready'); -import plaintextRelativeToTransformReady = require('./plaintext-relative-to-transform-ready'); +import plaintextAbsoluteToTransformReady from './plaintext-absolute-to-transform-ready'; +import plaintextRelativeToTransformReady from './plaintext-relative-to-transform-ready'; import plaintextToTransformReady = require('./plaintext-to-transform-ready'); -import relativeToAbsolute = require('./relative-to-absolute'); -import relativeToTransformReady = require('./relative-to-transform-ready'); +import relativeToAbsolute from './relative-to-absolute'; +import relativeToTransformReady from './relative-to-transform-ready'; import replacePermalink = require('./replace-permalink'); import stripSubdirectoryFromPath = require('./strip-subdirectory-from-path'); import toTransformReady = require('./to-transform-ready'); -import transformReadyToAbsolute = require('./transform-ready-to-absolute'); -import transformReadyToRelative = require('./transform-ready-to-relative'); +import transformReadyToAbsolute from './transform-ready-to-absolute'; +import transformReadyToRelative from './transform-ready-to-relative'; import urlJoin = require('./url-join'); export = { diff --git a/packages/url-utils/lib/utils/lexical-absolute-to-relative.ts b/packages/url-utils/lib/utils/lexical-absolute-to-relative.ts index 560fc467f..34f25c8fb 100644 --- a/packages/url-utils/lib/utils/lexical-absolute-to-relative.ts +++ b/packages/url-utils/lib/utils/lexical-absolute-to-relative.ts @@ -1,4 +1,4 @@ -import absoluteToRelative = require('./absolute-to-relative'); +import absoluteToRelative from './absolute-to-relative'; import lexicalTransform = require('./lexical-transform'); interface LexicalAbsoluteToRelativeOptions { diff --git a/packages/url-utils/lib/utils/lexical-absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/lexical-absolute-to-transform-ready.ts index acf4cebb1..15d8336f4 100644 --- a/packages/url-utils/lib/utils/lexical-absolute-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/lexical-absolute-to-transform-ready.ts @@ -1,4 +1,4 @@ -import absoluteToTransformReady = require('./absolute-to-transform-ready'); +import absoluteToTransformReady from './absolute-to-transform-ready'; import lexicalTransform = require('./lexical-transform'); interface LexicalAbsoluteToTransformReadyOptions { diff --git a/packages/url-utils/lib/utils/lexical-relative-to-absolute.ts b/packages/url-utils/lib/utils/lexical-relative-to-absolute.ts index e32c0c819..94bd4ee97 100644 --- a/packages/url-utils/lib/utils/lexical-relative-to-absolute.ts +++ b/packages/url-utils/lib/utils/lexical-relative-to-absolute.ts @@ -1,4 +1,4 @@ -import relativeToAbsolute = require('./relative-to-absolute'); +import relativeToAbsolute from './relative-to-absolute'; import lexicalTransform = require('./lexical-transform'); interface LexicalRelativeToAbsoluteOptions { diff --git a/packages/url-utils/lib/utils/lexical-relative-to-transform-ready.ts b/packages/url-utils/lib/utils/lexical-relative-to-transform-ready.ts index aed4a6ff5..cd9029d0c 100644 --- a/packages/url-utils/lib/utils/lexical-relative-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/lexical-relative-to-transform-ready.ts @@ -1,4 +1,4 @@ -import relativeToTransformReady = require('./relative-to-transform-ready'); +import relativeToTransformReady from './relative-to-transform-ready'; import lexicalTransform = require('./lexical-transform'); interface LexicalRelativeToTransformReadyOptions { diff --git a/packages/url-utils/lib/utils/lexical-to-transform-ready.ts b/packages/url-utils/lib/utils/lexical-to-transform-ready.ts index 4679e590f..f3032e5fa 100644 --- a/packages/url-utils/lib/utils/lexical-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/lexical-to-transform-ready.ts @@ -9,11 +9,12 @@ interface LexicalToTransformReadyOptions { } function lexicalToTransformReady(lexical: string, siteUrl: string, itemPath?: string | LexicalToTransformReadyOptions | null, options?: LexicalToTransformReadyOptions): string { + let actualItemPath: string | null | undefined = itemPath as string | null | undefined; if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + options = itemPath as LexicalToTransformReadyOptions; + actualItemPath = null; } - const absolute = lexicalRelativeToAbsolute(lexical, siteUrl, itemPath as string | null, options); + const absolute = lexicalRelativeToAbsolute(lexical, siteUrl, actualItemPath as string | null, options); return lexicalAbsoluteToTransformReady(absolute, siteUrl, options); } diff --git a/packages/url-utils/lib/utils/markdown-absolute-to-relative.ts b/packages/url-utils/lib/utils/markdown-absolute-to-relative.ts index fa5988ffc..c71123f53 100644 --- a/packages/url-utils/lib/utils/markdown-absolute-to-relative.ts +++ b/packages/url-utils/lib/utils/markdown-absolute-to-relative.ts @@ -1,5 +1,5 @@ import markdownTransform = require('./markdown-transform'); -import absoluteToRelative = require('./absolute-to-relative'); +import absoluteToRelative from './absolute-to-relative'; import htmlAbsoluteToRelative = require('./html-absolute-to-relative'); interface MarkdownAbsoluteToRelativeOptions { diff --git a/packages/url-utils/lib/utils/markdown-absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/markdown-absolute-to-transform-ready.ts index 83d39aac6..0f1fd8eae 100644 --- a/packages/url-utils/lib/utils/markdown-absolute-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/markdown-absolute-to-transform-ready.ts @@ -1,6 +1,6 @@ import markdownTransform = require('./markdown-transform'); -import absoluteToTransformReady = require('./absolute-to-transform-ready'); -import htmlAbsoluteToTransformReady = require('./html-absolute-to-transform-ready'); +import absoluteToTransformReady from './absolute-to-transform-ready'; +import htmlAbsoluteToTransformReady from './html-absolute-to-transform-ready'; interface MarkdownAbsoluteToTransformReadyOptions { assetsOnly?: boolean; diff --git a/packages/url-utils/lib/utils/markdown-relative-to-absolute.ts b/packages/url-utils/lib/utils/markdown-relative-to-absolute.ts index c0845cdf4..599f33816 100644 --- a/packages/url-utils/lib/utils/markdown-relative-to-absolute.ts +++ b/packages/url-utils/lib/utils/markdown-relative-to-absolute.ts @@ -1,6 +1,6 @@ import markdownTransform = require('./markdown-transform'); import htmlRelativeToAbsolute = require('./html-relative-to-absolute'); -import relativeToAbsolute = require('./relative-to-absolute'); +import relativeToAbsolute from './relative-to-absolute'; interface MarkdownRelativeToAbsoluteOptions { assetsOnly?: boolean; diff --git a/packages/url-utils/lib/utils/markdown-relative-to-transform-ready.ts b/packages/url-utils/lib/utils/markdown-relative-to-transform-ready.ts index 00dd4e719..16d7cc838 100644 --- a/packages/url-utils/lib/utils/markdown-relative-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/markdown-relative-to-transform-ready.ts @@ -1,6 +1,6 @@ import markdownTransform = require('./markdown-transform'); -import htmlRelativeToTransformReady = require('./html-relative-to-transform-ready'); -import relativeToTransformReady = require('./relative-to-transform-ready'); +import htmlRelativeToTransformReady from './html-relative-to-transform-ready'; +import relativeToTransformReady from './relative-to-transform-ready'; interface MarkdownRelativeToTransformReadyOptions { assetsOnly?: boolean; diff --git a/packages/url-utils/lib/utils/markdown-to-transform-ready.ts b/packages/url-utils/lib/utils/markdown-to-transform-ready.ts index 50284654d..e1d44b510 100644 --- a/packages/url-utils/lib/utils/markdown-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/markdown-to-transform-ready.ts @@ -7,11 +7,12 @@ interface MarkdownToTransformReadyOptions { } function markdownToTransformReady(markdown: string, siteUrl: string, itemPath?: string | MarkdownToTransformReadyOptions | null, options?: MarkdownToTransformReadyOptions): string { + let actualItemPath: string | null | undefined = itemPath as string | null | undefined; if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + options = itemPath as MarkdownToTransformReadyOptions; + actualItemPath = null; } - const absolute = markdownRelativeToAbsolute(markdown, siteUrl, itemPath || null, options); + const absolute = markdownRelativeToAbsolute(markdown, siteUrl, actualItemPath || null, options); return markdownAbsoluteToTransformReady(absolute, siteUrl, options); } diff --git a/packages/url-utils/lib/utils/mobiledoc-absolute-to-relative.ts b/packages/url-utils/lib/utils/mobiledoc-absolute-to-relative.ts index 21bacd7e2..58d8d11db 100644 --- a/packages/url-utils/lib/utils/mobiledoc-absolute-to-relative.ts +++ b/packages/url-utils/lib/utils/mobiledoc-absolute-to-relative.ts @@ -1,4 +1,4 @@ -import absoluteToRelative = require('./absolute-to-relative'); +import absoluteToRelative from './absolute-to-relative'; import mobiledocTransform = require('./mobiledoc-transform'); interface MobiledocAbsoluteToRelativeOptions { diff --git a/packages/url-utils/lib/utils/mobiledoc-absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/mobiledoc-absolute-to-transform-ready.ts index 926f56ad8..fcce2bea1 100644 --- a/packages/url-utils/lib/utils/mobiledoc-absolute-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/mobiledoc-absolute-to-transform-ready.ts @@ -1,4 +1,4 @@ -import absoluteToTransformReady = require('./absolute-to-transform-ready'); +import absoluteToTransformReady from './absolute-to-transform-ready'; import mobiledocTransform = require('./mobiledoc-transform'); interface MobiledocAbsoluteToTransformReadyOptions { diff --git a/packages/url-utils/lib/utils/mobiledoc-relative-to-absolute.ts b/packages/url-utils/lib/utils/mobiledoc-relative-to-absolute.ts index c477f395e..93fb305c8 100644 --- a/packages/url-utils/lib/utils/mobiledoc-relative-to-absolute.ts +++ b/packages/url-utils/lib/utils/mobiledoc-relative-to-absolute.ts @@ -1,4 +1,4 @@ -import relativeToAbsolute = require('./relative-to-absolute'); +import relativeToAbsolute from './relative-to-absolute'; import mobiledocTransform = require('./mobiledoc-transform'); interface MobiledocRelativeToAbsoluteOptions { diff --git a/packages/url-utils/lib/utils/mobiledoc-relative-to-transform-ready.ts b/packages/url-utils/lib/utils/mobiledoc-relative-to-transform-ready.ts index 8dc117aea..521485896 100644 --- a/packages/url-utils/lib/utils/mobiledoc-relative-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/mobiledoc-relative-to-transform-ready.ts @@ -1,4 +1,4 @@ -import relativeToTransformReady = require('./relative-to-transform-ready'); +import relativeToTransformReady from './relative-to-transform-ready'; import mobiledocTransform = require('./mobiledoc-transform'); interface MobiledocRelativeToTransformReadyOptions { diff --git a/packages/url-utils/lib/utils/plaintext-absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/plaintext-absolute-to-transform-ready.ts index f17325d86..028c90938 100644 --- a/packages/url-utils/lib/utils/plaintext-absolute-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/plaintext-absolute-to-transform-ready.ts @@ -1,7 +1,7 @@ import {URL} from 'url'; -import absoluteToTransformReady = require('./absolute-to-transform-ready'); +import absoluteToTransformReady from './absolute-to-transform-ready'; -interface PlaintextAbsoluteToTransformReadyOptions { +export interface PlaintextAbsoluteToTransformReadyOptions { replacementStr?: string; withoutSubdirectory?: boolean; assetsOnly?: boolean; @@ -12,7 +12,7 @@ function escapeRegExp(string: string): string { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } -const plaintextAbsoluteToTransformReady = function plaintextAbsoluteToTransformReady(plaintext: string, rootUrl: string, itemPath?: string | PlaintextAbsoluteToTransformReadyOptions, options?: PlaintextAbsoluteToTransformReadyOptions): string { +export const plaintextAbsoluteToTransformReady = function plaintextAbsoluteToTransformReady(plaintext: string, rootUrl: string, itemPath?: string | PlaintextAbsoluteToTransformReadyOptions, options?: PlaintextAbsoluteToTransformReadyOptions): string { // itemPath is optional, if it's an object may be the options param instead if (typeof itemPath === 'object' && !options) { options = itemPath; @@ -31,4 +31,4 @@ const plaintextAbsoluteToTransformReady = function plaintextAbsoluteToTransformR }); }; -export = plaintextAbsoluteToTransformReady; +export default plaintextAbsoluteToTransformReady; diff --git a/packages/url-utils/lib/utils/plaintext-relative-to-transform-ready.ts b/packages/url-utils/lib/utils/plaintext-relative-to-transform-ready.ts index 9d8fde710..6a6818711 100644 --- a/packages/url-utils/lib/utils/plaintext-relative-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/plaintext-relative-to-transform-ready.ts @@ -1,14 +1,14 @@ import {URL} from 'url'; -import relativeToTransformReady = require('./relative-to-transform-ready'); +import relativeToTransformReady from './relative-to-transform-ready'; -interface PlaintextRelativeToTransformReadyOptions { +export interface PlaintextRelativeToTransformReadyOptions { replacementStr?: string; staticImageUrlPrefix?: string; assetsOnly?: boolean; secure?: boolean; } -const plaintextRelativeToTransformReady = function plaintextRelativeToTransformReady(plaintext: string, rootUrl: string, itemPath?: string | PlaintextRelativeToTransformReadyOptions, options?: PlaintextRelativeToTransformReadyOptions): string { +export const plaintextRelativeToTransformReady = function plaintextRelativeToTransformReady(plaintext: string, rootUrl: string, itemPath?: string | PlaintextRelativeToTransformReadyOptions, options?: PlaintextRelativeToTransformReadyOptions): string { // itemPath is optional, if it's an object may be the options param instead if (typeof itemPath === 'object' && !options) { options = itemPath; @@ -23,4 +23,4 @@ const plaintextRelativeToTransformReady = function plaintextRelativeToTransformR }); }; -export = plaintextRelativeToTransformReady; +export default plaintextRelativeToTransformReady; diff --git a/packages/url-utils/lib/utils/plaintext-to-transform-ready.ts b/packages/url-utils/lib/utils/plaintext-to-transform-ready.ts index e975145ff..83b2a8508 100644 --- a/packages/url-utils/lib/utils/plaintext-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/plaintext-to-transform-ready.ts @@ -1,6 +1,6 @@ import {URL} from 'url'; -import plaintextRelativeToTransformReady = require('./plaintext-relative-to-transform-ready'); -import plaintextAbsoluteToTransformReady = require('./plaintext-absolute-to-transform-ready'); +import plaintextRelativeToTransformReady from './plaintext-relative-to-transform-ready'; +import plaintextAbsoluteToTransformReady from './plaintext-absolute-to-transform-ready'; interface PlaintextToTransformReadyOptions { replacementStr?: string; diff --git a/packages/url-utils/lib/utils/relative-to-absolute.ts b/packages/url-utils/lib/utils/relative-to-absolute.ts index 71778d3d5..2985df951 100644 --- a/packages/url-utils/lib/utils/relative-to-absolute.ts +++ b/packages/url-utils/lib/utils/relative-to-absolute.ts @@ -11,7 +11,7 @@ import urlJoin = require('./url-join'); // this when all root-relative paths are treated as subdir-relative we have to // rely on subdirectory deduplication. -interface RelativeToAbsoluteOptions { +export interface RelativeToAbsoluteOptions { assetsOnly?: boolean; staticImageUrlPrefix?: string; secure?: boolean; @@ -27,17 +27,18 @@ interface RelativeToAbsoluteOptions { * @param {object} options * @returns {string} The passed in url or an absolute URL using */ -const relativeToAbsolute = function relativeToAbsolute(path: string, rootUrl: string, itemPath?: string | RelativeToAbsoluteOptions | null, _options?: RelativeToAbsoluteOptions): string { +export const relativeToAbsolute = function relativeToAbsolute(path: string, rootUrl: string, itemPath?: string | RelativeToAbsoluteOptions | null, _options?: RelativeToAbsoluteOptions): string { // itemPath is optional, if it's an object it may be the options param instead + let actualItemPath: string | null | undefined = itemPath as string | null | undefined; if (typeof itemPath === 'object' && !_options) { - _options = itemPath; - itemPath = null; + _options = itemPath as RelativeToAbsoluteOptions; + actualItemPath = null; } // 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 (actualItemPath && actualItemPath.match(/^http/)) { + const itemUrl = new URL(actualItemPath); + actualItemPath = itemUrl.pathname; } const defaultOptions: RelativeToAbsoluteOptions = { @@ -76,7 +77,7 @@ const relativeToAbsolute = function relativeToAbsolute(path: string, rootUrl: st } // return the path as-is if it's not root-relative and we have no itemPath - if (!itemPath && !path.match(/^\//)) { + if (!actualItemPath && !path.match(/^\//)) { return path; } @@ -86,7 +87,7 @@ const relativeToAbsolute = function relativeToAbsolute(path: string, rootUrl: st } const parsedRootUrl = new URL(rootUrl); - const basePath = path.startsWith('/') ? '' : itemPath || ''; + const basePath = path.startsWith('/') ? '' : actualItemPath || ''; const fullPath = urlJoin([parsedRootUrl.pathname, basePath, path], {rootUrl}); const absoluteUrl = new URL(fullPath, rootUrl); @@ -97,4 +98,4 @@ const relativeToAbsolute = function relativeToAbsolute(path: string, rootUrl: st return absoluteUrl.toString(); }; -export = relativeToAbsolute; +export default relativeToAbsolute; diff --git a/packages/url-utils/lib/utils/relative-to-transform-ready.ts b/packages/url-utils/lib/utils/relative-to-transform-ready.ts index e4252d803..d140a1dce 100644 --- a/packages/url-utils/lib/utils/relative-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/relative-to-transform-ready.ts @@ -1,18 +1,19 @@ import {URL} from 'url'; -import relativeToAbsolute = require('./relative-to-absolute'); +import relativeToAbsolute from './relative-to-absolute'; -interface RelativeToTransformReadyOptions { +export interface RelativeToTransformReadyOptions { replacementStr?: string; staticImageUrlPrefix?: string; assetsOnly?: boolean; secure?: boolean; } -const relativeToTransformReady = function (url: string, root: string, itemPath?: string | RelativeToTransformReadyOptions | null, _options?: RelativeToTransformReadyOptions): string { +export const relativeToTransformReady = function (url: string, root: string, itemPath?: string | RelativeToTransformReadyOptions | null, _options?: RelativeToTransformReadyOptions): string { // itemPath is optional, if it's an object may be the options param instead + let actualItemPath: string | null | undefined = itemPath as string | null | undefined; if (typeof itemPath === 'object' && !_options) { - _options = itemPath; - itemPath = null; + _options = itemPath as RelativeToTransformReadyOptions; + actualItemPath = null; } const defaultOptions: RelativeToTransformReadyOptions = { @@ -25,7 +26,7 @@ const relativeToTransformReady = function (url: string, root: string, itemPath?: const options = Object.assign({}, defaultOptions, _options, overrideOptions); // convert to absolute - const absoluteUrl = relativeToAbsolute(url, root, itemPath || null, options); + const absoluteUrl = relativeToAbsolute(url, root, actualItemPath || null, options); if (absoluteUrl === url) { return url; @@ -47,4 +48,4 @@ const relativeToTransformReady = function (url: string, root: string, itemPath?: return url; }; -export = relativeToTransformReady; +export default relativeToTransformReady; diff --git a/packages/url-utils/lib/utils/to-transform-ready.ts b/packages/url-utils/lib/utils/to-transform-ready.ts index f58d76608..02a32a1bf 100644 --- a/packages/url-utils/lib/utils/to-transform-ready.ts +++ b/packages/url-utils/lib/utils/to-transform-ready.ts @@ -1,5 +1,5 @@ -import relativeToAbsolute = require('./relative-to-absolute'); -import absoluteToTransformReady = require('./absolute-to-transform-ready'); +import relativeToAbsolute from './relative-to-absolute'; +import absoluteToTransformReady from './absolute-to-transform-ready'; interface ToTransformReadyOptions { replacementStr?: string; @@ -9,11 +9,12 @@ interface ToTransformReadyOptions { } function toTransformReady(url: string, siteUrl: string, itemPath?: string | ToTransformReadyOptions | null, options?: ToTransformReadyOptions): string { + let actualItemPath: string | null | undefined = itemPath as string | null | undefined; if (typeof itemPath === 'object' && !options) { - options = itemPath; - itemPath = null; + options = itemPath as ToTransformReadyOptions; + actualItemPath = null; } - const absoluteUrl = relativeToAbsolute(url, siteUrl, itemPath || null, options); + const absoluteUrl = relativeToAbsolute(url, siteUrl, actualItemPath || null, options); return absoluteToTransformReady(absoluteUrl, siteUrl, options); } diff --git a/packages/url-utils/lib/utils/transform-ready-to-absolute.ts b/packages/url-utils/lib/utils/transform-ready-to-absolute.ts index a7b486f4c..2a9b41941 100644 --- a/packages/url-utils/lib/utils/transform-ready-to-absolute.ts +++ b/packages/url-utils/lib/utils/transform-ready-to-absolute.ts @@ -2,11 +2,11 @@ function escapeRegExp(string: string): string { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } -interface TransformReadyToAbsoluteOptions { +export interface TransformReadyToAbsoluteOptions { replacementStr?: string; } -const transformReadyToAbsolute = function (str = '', root: string, _options: TransformReadyToAbsoluteOptions = {}): string { +export const transformReadyToAbsolute = function (str = '', root: string, _options: TransformReadyToAbsoluteOptions = {}): string { const defaultOptions: TransformReadyToAbsoluteOptions = { replacementStr: '__GHOST_URL__' }; @@ -21,4 +21,4 @@ const transformReadyToAbsolute = function (str = '', root: string, _options: Tra return str.replace(replacementRegex, root.replace(/\/$/, '')); }; -export = transformReadyToAbsolute; +export default transformReadyToAbsolute; diff --git a/packages/url-utils/lib/utils/transform-ready-to-relative.ts b/packages/url-utils/lib/utils/transform-ready-to-relative.ts index 903c3285b..3cbaaf7fb 100644 --- a/packages/url-utils/lib/utils/transform-ready-to-relative.ts +++ b/packages/url-utils/lib/utils/transform-ready-to-relative.ts @@ -4,11 +4,11 @@ function escapeRegExp(string: string): string { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } -interface TransformReadyToRelativeOptions { +export interface TransformReadyToRelativeOptions { replacementStr?: string; } -const transformReadyToRelative = function (str = '', root: string, _options: TransformReadyToRelativeOptions = {}): string { +export const transformReadyToRelative = function (str = '', root: string, _options: TransformReadyToRelativeOptions = {}): string { const defaultOptions: TransformReadyToRelativeOptions = { replacementStr: '__GHOST_URL__' }; @@ -27,4 +27,4 @@ const transformReadyToRelative = function (str = '', root: string, _options: Tra return str.replace(replacementRegex, subdir); }; -export = transformReadyToRelative; +export default transformReadyToRelative; diff --git a/yarn.lock b/yarn.lock index 3a0f0ef7d..f99b02da4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3356,6 +3356,13 @@ dependencies: "@types/deep-eql" "*" +"@types/cheerio@^0.22.35": + version "0.22.35" + resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.35.tgz#0d16dc1f24d426231c181b9c31847f673867595f" + integrity sha512-yD57BchKRvTV+JD53UZ6PD8KWY5g5rvvMLRnZR3EQBCZXiDT/HR+pKpMzFGlWNhFrXlo7VPZXtKvIEwZkAWOIA== + dependencies: + "@types/node" "*" + "@types/color-convert@*": version "2.0.4" resolved "https://registry.yarnpkg.com/@types/color-convert/-/color-convert-2.0.4.tgz#843398ae71e951dc5415d202dfd5e43108823eeb" @@ -3407,6 +3414,11 @@ dependencies: "@types/node" "*" +"@types/lodash@^4.17.13": + version "4.17.20" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.20.tgz#1ca77361d7363432d29f5e55950d9ec1e1c6ea93" + integrity sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA== + "@types/minimatch@^3.0.3": version "3.0.5" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" @@ -3436,6 +3448,13 @@ dependencies: undici-types "~6.21.0" +"@types/node@^22.10.2": + version "22.18.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.18.12.tgz#e165d87bc25d7bf6d3657035c914db7485de84fb" + integrity sha512-BICHQ67iqxQGFSzfCFTT7MRQ5XcBjG5aeKh5Ok38UBbPe5fxTyE+aHFxwVrGyr8GNlqFMLKD1D3P2K/1ks8tog== + dependencies: + undici-types "~6.21.0" + "@types/normalize-package-data@^2.4.0": version "2.4.4" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" @@ -12214,7 +12233,7 @@ typescript@5.8.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4" integrity sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ== -typescript@5.9.3: +typescript@5.9.3, typescript@^5.7.2: version "5.9.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== From 774b9b3d5e7600c4223068989bada861a34a1b10 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Oct 2025 03:59:05 +0000 Subject: [PATCH 12/14] chore(url-utils): Configure ESLint for TypeScript files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add TypeScript parser configuration for .ts files - Disable conflicting ESLint rules for TypeScript - Allows linting to work with both JS and TS files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- packages/url-utils/.eslintrc.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/url-utils/.eslintrc.js b/packages/url-utils/.eslintrc.js index c9c1bcb52..17fb214aa 100644 --- a/packages/url-utils/.eslintrc.js +++ b/packages/url-utils/.eslintrc.js @@ -2,5 +2,20 @@ module.exports = { plugins: ['ghost'], extends: [ 'plugin:ghost/node' + ], + overrides: [ + { + files: ['*.ts'], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 2020, + sourceType: 'module' + }, + rules: { + // Disable rules that conflict with TypeScript + 'no-unused-vars': 'off', + 'no-undef': 'off' + } + } ] }; From a23c914729514f61150ca4c47ef919fd312132a6 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Oct 2025 04:17:09 +0000 Subject: [PATCH 13/14] refactor(url-utils): Standardize all exports to use export default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the codebase used a mix of `export =` and `export default`. This standardizes on `export default` throughout for consistency and better ES6 module compatibility. Changes: - Convert all `export = Thing` to `export default Thing` - Update all imports from `import x = require('./y')` to `import x from './y'` - Affects 37+ files including all utilities and main classes All tests passing, build succeeds. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- packages/url-utils/index.ts | 4 +- packages/url-utils/lib/UrlUtils.ts | 14 ++--- .../lib/utils/absolute-to-relative.ts | 2 +- .../lib/utils/deduplicate-double-slashes.ts | 2 +- .../lib/utils/deduplicate-subdirectory.ts | 2 +- .../lib/utils/html-absolute-to-relative.ts | 4 +- .../utils/html-absolute-to-transform-ready.ts | 2 +- .../lib/utils/html-relative-to-absolute.ts | 4 +- .../utils/html-relative-to-transform-ready.ts | 2 +- .../lib/utils/html-to-transform-ready.ts | 4 +- .../url-utils/lib/utils/html-transform.ts | 2 +- packages/url-utils/lib/utils/index.ts | 54 +++++++++---------- packages/url-utils/lib/utils/is-ssl.ts | 2 +- .../lib/utils/lexical-absolute-to-relative.ts | 4 +- .../lexical-absolute-to-transform-ready.ts | 4 +- .../lib/utils/lexical-relative-to-absolute.ts | 4 +- .../lexical-relative-to-transform-ready.ts | 4 +- .../lib/utils/lexical-to-transform-ready.ts | 6 +-- .../url-utils/lib/utils/lexical-transform.ts | 2 +- .../utils/markdown-absolute-to-relative.ts | 6 +-- .../markdown-absolute-to-transform-ready.ts | 4 +- .../utils/markdown-relative-to-absolute.ts | 6 +-- .../markdown-relative-to-transform-ready.ts | 4 +- .../lib/utils/markdown-to-transform-ready.ts | 6 +-- .../url-utils/lib/utils/markdown-transform.ts | 2 +- .../utils/mobiledoc-absolute-to-relative.ts | 4 +- .../mobiledoc-absolute-to-transform-ready.ts | 4 +- .../utils/mobiledoc-relative-to-absolute.ts | 4 +- .../mobiledoc-relative-to-transform-ready.ts | 4 +- .../lib/utils/mobiledoc-to-transform-ready.ts | 6 +-- .../lib/utils/mobiledoc-transform.ts | 2 +- .../lib/utils/plaintext-to-transform-ready.ts | 2 +- .../lib/utils/relative-to-absolute.ts | 2 +- .../url-utils/lib/utils/replace-permalink.ts | 4 +- .../lib/utils/strip-subdirectory-from-path.ts | 2 +- .../url-utils/lib/utils/to-transform-ready.ts | 2 +- packages/url-utils/lib/utils/url-join.ts | 4 +- 37 files changed, 95 insertions(+), 95 deletions(-) diff --git a/packages/url-utils/index.ts b/packages/url-utils/index.ts index a608509de..fd5cbe3f7 100644 --- a/packages/url-utils/index.ts +++ b/packages/url-utils/index.ts @@ -1,3 +1,3 @@ -import UrlUtils = require('./lib/UrlUtils'); +import UrlUtils from './lib/UrlUtils'; -export = UrlUtils; +export default UrlUtils; diff --git a/packages/url-utils/lib/UrlUtils.ts b/packages/url-utils/lib/UrlUtils.ts index a6becce7a..2f1031ded 100644 --- a/packages/url-utils/lib/UrlUtils.ts +++ b/packages/url-utils/lib/UrlUtils.ts @@ -1,6 +1,6 @@ // Contains all path information to be used throughout the codebase. import * as _ from 'lodash'; -const utils = require('./utils'); +import utils from './utils'; interface UrlUtilsConfig { slugs: string[] | null; @@ -343,7 +343,7 @@ class UrlUtils { } const _options = assignOptions({}, defaultOptions, options || {}); - return utils.htmlRelativeToAbsolute(html, this.getSiteUrl(), itemPathOrOptions, _options); + return utils.htmlRelativeToAbsolute(html, this.getSiteUrl(), itemPathOrOptions || null, _options); } htmlRelativeToTransformReady(html: string, options?: TransformOptions): string; @@ -404,7 +404,7 @@ class UrlUtils { } const _options = assignOptions({}, defaultOptions, options || {}); - return utils.markdownRelativeToAbsolute(markdown, this.getSiteUrl(), itemPathOrOptions, _options); + return utils.markdownRelativeToAbsolute(markdown, this.getSiteUrl(), itemPathOrOptions || null, _options); } markdownRelativeToTransformReady(markdown: string, options?: TransformOptions): string; @@ -421,7 +421,7 @@ class UrlUtils { } const _options = assignOptions({}, defaultOptions, options || {}); - return utils.markdownRelativeToTransformReady(markdown, this.getSiteUrl(), itemPathOrOptions, _options); + return utils.markdownRelativeToTransformReady(markdown, this.getSiteUrl(), itemPathOrOptions || null, _options); } markdownAbsoluteToRelative(markdown: string, options: TransformOptions = {}): string { @@ -545,7 +545,7 @@ class UrlUtils { } const _options = assignOptions({}, defaultOptions, options || {}); - return utils.lexicalRelativeToAbsolute(serializedLexical, this.getSiteUrl(), itemPathOrOptions, _options); + return utils.lexicalRelativeToAbsolute(serializedLexical, this.getSiteUrl(), itemPathOrOptions || null, _options); } lexicalRelativeToTransformReady(serializedLexical: string, options?: TransformOptions): string; @@ -563,7 +563,7 @@ class UrlUtils { } const _options = assignOptions({}, defaultOptions, options || {}); - return utils.lexicalRelativeToTransformReady(serializedLexical, this.getSiteUrl(), itemPathOrOptions, _options); + return utils.lexicalRelativeToTransformReady(serializedLexical, this.getSiteUrl(), itemPathOrOptions || null, _options); } lexicalAbsoluteToRelative(serializedLexical: string, options: TransformOptions = {}): string { @@ -642,4 +642,4 @@ class UrlUtils { } } -export = UrlUtils; +export default UrlUtils; diff --git a/packages/url-utils/lib/utils/absolute-to-relative.ts b/packages/url-utils/lib/utils/absolute-to-relative.ts index 311f85f2d..c23179365 100644 --- a/packages/url-utils/lib/utils/absolute-to-relative.ts +++ b/packages/url-utils/lib/utils/absolute-to-relative.ts @@ -1,6 +1,6 @@ // require the whatwg compatible URL library (same behaviour in node and browser) import {URL} from 'url'; -import stripSubdirectoryFromPath = require('./strip-subdirectory-from-path'); +import stripSubdirectoryFromPath from './strip-subdirectory-from-path'; export interface AbsoluteToRelativeOptions { ignoreProtocol?: boolean; diff --git a/packages/url-utils/lib/utils/deduplicate-double-slashes.ts b/packages/url-utils/lib/utils/deduplicate-double-slashes.ts index c374d57d5..afbcc7fdd 100644 --- a/packages/url-utils/lib/utils/deduplicate-double-slashes.ts +++ b/packages/url-utils/lib/utils/deduplicate-double-slashes.ts @@ -2,4 +2,4 @@ function deduplicateDoubleSlashes(url: string): string { return url.replace(/\/\//g, '/'); } -export = deduplicateDoubleSlashes; +export default deduplicateDoubleSlashes; diff --git a/packages/url-utils/lib/utils/deduplicate-subdirectory.ts b/packages/url-utils/lib/utils/deduplicate-subdirectory.ts index a749eefa1..c6b9c6e84 100644 --- a/packages/url-utils/lib/utils/deduplicate-subdirectory.ts +++ b/packages/url-utils/lib/utils/deduplicate-subdirectory.ts @@ -28,4 +28,4 @@ const deduplicateSubdirectory = function deduplicateSubdirectory(url: string, ro return url.replace(subdirRegex, `$1${subdir}/`); }; -export = deduplicateSubdirectory; +export default deduplicateSubdirectory; diff --git a/packages/url-utils/lib/utils/html-absolute-to-relative.ts b/packages/url-utils/lib/utils/html-absolute-to-relative.ts index e4d47de0a..495f437ab 100644 --- a/packages/url-utils/lib/utils/html-absolute-to-relative.ts +++ b/packages/url-utils/lib/utils/html-absolute-to-relative.ts @@ -1,4 +1,4 @@ -import htmlTransform = require('./html-transform'); +import htmlTransform from './html-transform'; import absoluteToRelative from './absolute-to-relative'; interface HtmlAbsoluteToRelativeOptions { @@ -24,4 +24,4 @@ function htmlAbsoluteToRelative(html = '', siteUrl: string, _options?: HtmlAbsol return htmlTransform(html, siteUrl, transformFunction, '', options); } -export = htmlAbsoluteToRelative; +export default htmlAbsoluteToRelative; diff --git a/packages/url-utils/lib/utils/html-absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/html-absolute-to-transform-ready.ts index 3f8982e12..53fe955ce 100644 --- a/packages/url-utils/lib/utils/html-absolute-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/html-absolute-to-transform-ready.ts @@ -1,4 +1,4 @@ -import htmlTransform = require('./html-transform'); +import htmlTransform from './html-transform'; import absoluteToTransformReady from './absolute-to-transform-ready'; export interface HtmlAbsoluteToTransformReadyOptions { diff --git a/packages/url-utils/lib/utils/html-relative-to-absolute.ts b/packages/url-utils/lib/utils/html-relative-to-absolute.ts index 764a339f5..357f0d14f 100644 --- a/packages/url-utils/lib/utils/html-relative-to-absolute.ts +++ b/packages/url-utils/lib/utils/html-relative-to-absolute.ts @@ -1,4 +1,4 @@ -import htmlTransform = require('./html-transform'); +import htmlTransform from './html-transform'; import relativeToAbsolute from './relative-to-absolute'; interface HtmlRelativeToAbsoluteOptions { @@ -21,4 +21,4 @@ function htmlRelativeToAbsolute(html = '', siteUrl: string, itemPath: string | H return htmlTransform(html, siteUrl, relativeToAbsolute, itemPath as string | null, options); } -export = htmlRelativeToAbsolute; +export default htmlRelativeToAbsolute; diff --git a/packages/url-utils/lib/utils/html-relative-to-transform-ready.ts b/packages/url-utils/lib/utils/html-relative-to-transform-ready.ts index edf51c9ee..2349ce76a 100644 --- a/packages/url-utils/lib/utils/html-relative-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/html-relative-to-transform-ready.ts @@ -1,4 +1,4 @@ -import htmlTransform = require('./html-transform'); +import htmlTransform from './html-transform'; import relativeToTransformReady from './relative-to-transform-ready'; export interface HtmlRelativeToTransformReadyOptions { diff --git a/packages/url-utils/lib/utils/html-to-transform-ready.ts b/packages/url-utils/lib/utils/html-to-transform-ready.ts index 2088b5ea5..538f4c370 100644 --- a/packages/url-utils/lib/utils/html-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/html-to-transform-ready.ts @@ -1,4 +1,4 @@ -import htmlRelativeToAbsolute = require('./html-relative-to-absolute'); +import htmlRelativeToAbsolute from './html-relative-to-absolute'; import htmlAbsoluteToTransformReady from './html-absolute-to-transform-ready'; interface HtmlToTransformReadyOptions { @@ -17,4 +17,4 @@ function htmlToTransformReady(html: string, siteUrl: string, itemPath?: string | return htmlAbsoluteToTransformReady(absolute, siteUrl, options); } -export = htmlToTransformReady; +export default htmlToTransformReady; diff --git a/packages/url-utils/lib/utils/html-transform.ts b/packages/url-utils/lib/utils/html-transform.ts index 8263a141a..07e5a54e6 100644 --- a/packages/url-utils/lib/utils/html-transform.ts +++ b/packages/url-utils/lib/utils/html-transform.ts @@ -155,4 +155,4 @@ function htmlTransform(html = '', siteUrl: string, transformFunction: TransformF return html; } -export = htmlTransform; +export default htmlTransform; diff --git a/packages/url-utils/lib/utils/index.ts b/packages/url-utils/lib/utils/index.ts index 1f3243c3d..fa202312d 100644 --- a/packages/url-utils/lib/utils/index.ts +++ b/packages/url-utils/lib/utils/index.ts @@ -1,41 +1,41 @@ import absoluteToRelative from './absolute-to-relative'; import absoluteToTransformReady from './absolute-to-transform-ready'; -import deduplicateDoubleSlashes = require('./deduplicate-double-slashes'); -import deduplicateSubdirectory = require('./deduplicate-subdirectory'); -import htmlAbsoluteToRelative = require('./html-absolute-to-relative'); -import htmlRelativeToAbsolute = require('./html-relative-to-absolute'); +import deduplicateDoubleSlashes from './deduplicate-double-slashes'; +import deduplicateSubdirectory from './deduplicate-subdirectory'; +import htmlAbsoluteToRelative from './html-absolute-to-relative'; +import htmlRelativeToAbsolute from './html-relative-to-absolute'; import htmlAbsoluteToTransformReady from './html-absolute-to-transform-ready'; import htmlRelativeToTransformReady from './html-relative-to-transform-ready'; -import htmlToTransformReady = require('./html-to-transform-ready'); -import isSSL = require('./is-ssl'); -import markdownAbsoluteToRelative = require('./markdown-absolute-to-relative'); -import markdownRelativeToAbsolute = require('./markdown-relative-to-absolute'); -import markdownAbsoluteToTransformReady = require('./markdown-absolute-to-transform-ready'); -import markdownRelativeToTransformReady = require('./markdown-relative-to-transform-ready'); -import markdownToTransformReady = require('./markdown-to-transform-ready'); -import mobiledocAbsoluteToRelative = require('./mobiledoc-absolute-to-relative'); -import mobiledocRelativeToAbsolute = require('./mobiledoc-relative-to-absolute'); -import mobiledocAbsoluteToTransformReady = require('./mobiledoc-absolute-to-transform-ready'); -import mobiledocRelativeToTransformReady = require('./mobiledoc-relative-to-transform-ready'); -import mobiledocToTransformReady = require('./mobiledoc-to-transform-ready'); -import lexicalAbsoluteToRelative = require('./lexical-absolute-to-relative'); -import lexicalRelativeToAbsolute = require('./lexical-relative-to-absolute'); -import lexicalAbsoluteToTransformReady = require('./lexical-absolute-to-transform-ready'); -import lexicalRelativeToTransformReady = require('./lexical-relative-to-transform-ready'); -import lexicalToTransformReady = require('./lexical-to-transform-ready'); +import htmlToTransformReady from './html-to-transform-ready'; +import isSSL from './is-ssl'; +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 lexicalAbsoluteToRelative from './lexical-absolute-to-relative'; +import lexicalRelativeToAbsolute from './lexical-relative-to-absolute'; +import lexicalAbsoluteToTransformReady from './lexical-absolute-to-transform-ready'; +import lexicalRelativeToTransformReady from './lexical-relative-to-transform-ready'; +import lexicalToTransformReady from './lexical-to-transform-ready'; import plaintextAbsoluteToTransformReady from './plaintext-absolute-to-transform-ready'; import plaintextRelativeToTransformReady from './plaintext-relative-to-transform-ready'; -import plaintextToTransformReady = require('./plaintext-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 = require('./replace-permalink'); -import stripSubdirectoryFromPath = require('./strip-subdirectory-from-path'); -import toTransformReady = require('./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 = require('./url-join'); +import urlJoin from './url-join'; -export = { +export default { absoluteToRelative, absoluteToTransformReady, deduplicateDoubleSlashes, diff --git a/packages/url-utils/lib/utils/is-ssl.ts b/packages/url-utils/lib/utils/is-ssl.ts index b024cfe5f..e4edee372 100644 --- a/packages/url-utils/lib/utils/is-ssl.ts +++ b/packages/url-utils/lib/utils/is-ssl.ts @@ -6,4 +6,4 @@ function isSSL(urlToParse: string): boolean { return protocol === 'https:'; } -export = isSSL; +export default isSSL; diff --git a/packages/url-utils/lib/utils/lexical-absolute-to-relative.ts b/packages/url-utils/lib/utils/lexical-absolute-to-relative.ts index 34f25c8fb..a4ea2d8aa 100644 --- a/packages/url-utils/lib/utils/lexical-absolute-to-relative.ts +++ b/packages/url-utils/lib/utils/lexical-absolute-to-relative.ts @@ -1,5 +1,5 @@ import absoluteToRelative from './absolute-to-relative'; -import lexicalTransform = require('./lexical-transform'); +import lexicalTransform from './lexical-transform'; interface LexicalAbsoluteToRelativeOptions { assetsOnly?: boolean; @@ -20,4 +20,4 @@ function lexicalAbsoluteToRelative(serializedLexical: string, siteUrl: string, _ return lexicalTransform(serializedLexical, siteUrl, transformFunction, null, options); } -export = lexicalAbsoluteToRelative; +export default lexicalAbsoluteToRelative; diff --git a/packages/url-utils/lib/utils/lexical-absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/lexical-absolute-to-transform-ready.ts index 15d8336f4..432a1ca87 100644 --- a/packages/url-utils/lib/utils/lexical-absolute-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/lexical-absolute-to-transform-ready.ts @@ -1,5 +1,5 @@ import absoluteToTransformReady from './absolute-to-transform-ready'; -import lexicalTransform = require('./lexical-transform'); +import lexicalTransform from './lexical-transform'; interface LexicalAbsoluteToTransformReadyOptions { assetsOnly?: boolean; @@ -20,4 +20,4 @@ function lexicalAbsoluteToTransformReady(serializedLexical: string, siteUrl: str return lexicalTransform(serializedLexical, siteUrl, transformFunction, null, options); } -export = lexicalAbsoluteToTransformReady; +export default lexicalAbsoluteToTransformReady; diff --git a/packages/url-utils/lib/utils/lexical-relative-to-absolute.ts b/packages/url-utils/lib/utils/lexical-relative-to-absolute.ts index 94bd4ee97..e9eec83c8 100644 --- a/packages/url-utils/lib/utils/lexical-relative-to-absolute.ts +++ b/packages/url-utils/lib/utils/lexical-relative-to-absolute.ts @@ -1,5 +1,5 @@ import relativeToAbsolute from './relative-to-absolute'; -import lexicalTransform = require('./lexical-transform'); +import lexicalTransform from './lexical-transform'; interface LexicalRelativeToAbsoluteOptions { assetsOnly?: boolean; @@ -16,4 +16,4 @@ function lexicalRelativeToAbsolute(serializedLexical: string, siteUrl: string, i return lexicalTransform(serializedLexical, siteUrl, relativeToAbsolute, itemPath, options); } -export = lexicalRelativeToAbsolute; +export default lexicalRelativeToAbsolute; diff --git a/packages/url-utils/lib/utils/lexical-relative-to-transform-ready.ts b/packages/url-utils/lib/utils/lexical-relative-to-transform-ready.ts index cd9029d0c..2c5069160 100644 --- a/packages/url-utils/lib/utils/lexical-relative-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/lexical-relative-to-transform-ready.ts @@ -1,5 +1,5 @@ import relativeToTransformReady from './relative-to-transform-ready'; -import lexicalTransform = require('./lexical-transform'); +import lexicalTransform from './lexical-transform'; interface LexicalRelativeToTransformReadyOptions { assetsOnly?: boolean; @@ -16,4 +16,4 @@ function lexicalRelativeToTransformReady(serializedLexical: string, siteUrl: str return lexicalTransform(serializedLexical, siteUrl, relativeToTransformReady, itemPath, options); } -export = lexicalRelativeToTransformReady; +export default lexicalRelativeToTransformReady; diff --git a/packages/url-utils/lib/utils/lexical-to-transform-ready.ts b/packages/url-utils/lib/utils/lexical-to-transform-ready.ts index f3032e5fa..adedeb523 100644 --- a/packages/url-utils/lib/utils/lexical-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/lexical-to-transform-ready.ts @@ -1,5 +1,5 @@ -import lexicalRelativeToAbsolute = require('./lexical-relative-to-absolute'); -import lexicalAbsoluteToTransformReady = require('./lexical-absolute-to-transform-ready'); +import lexicalRelativeToAbsolute from './lexical-relative-to-absolute'; +import lexicalAbsoluteToTransformReady from './lexical-absolute-to-transform-ready'; interface LexicalToTransformReadyOptions { assetsOnly?: boolean; @@ -18,4 +18,4 @@ function lexicalToTransformReady(lexical: string, siteUrl: string, itemPath?: st return lexicalAbsoluteToTransformReady(absolute, siteUrl, options); } -export = lexicalToTransformReady; +export default lexicalToTransformReady; diff --git a/packages/url-utils/lib/utils/lexical-transform.ts b/packages/url-utils/lib/utils/lexical-transform.ts index d380bca27..5ca308d71 100644 --- a/packages/url-utils/lib/utils/lexical-transform.ts +++ b/packages/url-utils/lib/utils/lexical-transform.ts @@ -91,4 +91,4 @@ function lexicalTransform(serializedLexical: string, siteUrl: string, transformF return JSON.stringify(lexical); } -export = lexicalTransform; +export default lexicalTransform; diff --git a/packages/url-utils/lib/utils/markdown-absolute-to-relative.ts b/packages/url-utils/lib/utils/markdown-absolute-to-relative.ts index c71123f53..e9c34d50a 100644 --- a/packages/url-utils/lib/utils/markdown-absolute-to-relative.ts +++ b/packages/url-utils/lib/utils/markdown-absolute-to-relative.ts @@ -1,6 +1,6 @@ -import markdownTransform = require('./markdown-transform'); +import markdownTransform from './markdown-transform'; import absoluteToRelative from './absolute-to-relative'; -import htmlAbsoluteToRelative = require('./html-absolute-to-relative'); +import htmlAbsoluteToRelative from './html-absolute-to-relative'; interface MarkdownAbsoluteToRelativeOptions { assetsOnly?: boolean; @@ -29,4 +29,4 @@ function markdownAbsoluteToRelative(markdown = '', siteUrl: string, _options: Ma return markdownTransform(markdown, siteUrl, transformFunctions, '', options); } -export = markdownAbsoluteToRelative; +export default markdownAbsoluteToRelative; diff --git a/packages/url-utils/lib/utils/markdown-absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/markdown-absolute-to-transform-ready.ts index 0f1fd8eae..e4832ca25 100644 --- a/packages/url-utils/lib/utils/markdown-absolute-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/markdown-absolute-to-transform-ready.ts @@ -1,4 +1,4 @@ -import markdownTransform = require('./markdown-transform'); +import markdownTransform from './markdown-transform'; import absoluteToTransformReady from './absolute-to-transform-ready'; import htmlAbsoluteToTransformReady from './html-absolute-to-transform-ready'; @@ -29,4 +29,4 @@ function markdownAbsoluteToTransformReady(markdown = '', siteUrl: string, _optio return markdownTransform(markdown, siteUrl, transformFunctions, '', options); } -export = markdownAbsoluteToTransformReady; +export default markdownAbsoluteToTransformReady; diff --git a/packages/url-utils/lib/utils/markdown-relative-to-absolute.ts b/packages/url-utils/lib/utils/markdown-relative-to-absolute.ts index 599f33816..bcf32df41 100644 --- a/packages/url-utils/lib/utils/markdown-relative-to-absolute.ts +++ b/packages/url-utils/lib/utils/markdown-relative-to-absolute.ts @@ -1,5 +1,5 @@ -import markdownTransform = require('./markdown-transform'); -import htmlRelativeToAbsolute = require('./html-relative-to-absolute'); +import markdownTransform from './markdown-transform'; +import htmlRelativeToAbsolute from './html-relative-to-absolute'; import relativeToAbsolute from './relative-to-absolute'; interface MarkdownRelativeToAbsoluteOptions { @@ -25,4 +25,4 @@ function markdownRelativeToAbsolute(markdown = '', siteUrl: string, itemPath: st return markdownTransform(markdown, siteUrl, transformFunctions, itemPath as string | null, options); } -export = markdownRelativeToAbsolute; +export default markdownRelativeToAbsolute; diff --git a/packages/url-utils/lib/utils/markdown-relative-to-transform-ready.ts b/packages/url-utils/lib/utils/markdown-relative-to-transform-ready.ts index 16d7cc838..b8eb5c2bf 100644 --- a/packages/url-utils/lib/utils/markdown-relative-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/markdown-relative-to-transform-ready.ts @@ -1,4 +1,4 @@ -import markdownTransform = require('./markdown-transform'); +import markdownTransform from './markdown-transform'; import htmlRelativeToTransformReady from './html-relative-to-transform-ready'; import relativeToTransformReady from './relative-to-transform-ready'; @@ -25,4 +25,4 @@ function markdownRelativeToTransformReady(markdown = '', siteUrl: string, itemPa return markdownTransform(markdown, siteUrl, transformFunctions, itemPath as string | null, options); } -export = markdownRelativeToTransformReady; +export default markdownRelativeToTransformReady; diff --git a/packages/url-utils/lib/utils/markdown-to-transform-ready.ts b/packages/url-utils/lib/utils/markdown-to-transform-ready.ts index e1d44b510..56c2bad2c 100644 --- a/packages/url-utils/lib/utils/markdown-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/markdown-to-transform-ready.ts @@ -1,5 +1,5 @@ -import markdownRelativeToAbsolute = require('./markdown-relative-to-absolute'); -import markdownAbsoluteToTransformReady = require('./markdown-absolute-to-transform-ready'); +import markdownRelativeToAbsolute from './markdown-relative-to-absolute'; +import markdownAbsoluteToTransformReady from './markdown-absolute-to-transform-ready'; interface MarkdownToTransformReadyOptions { assetsOnly?: boolean; @@ -16,4 +16,4 @@ function markdownToTransformReady(markdown: string, siteUrl: string, itemPath?: return markdownAbsoluteToTransformReady(absolute, siteUrl, options); } -export = markdownToTransformReady; +export default markdownToTransformReady; diff --git a/packages/url-utils/lib/utils/markdown-transform.ts b/packages/url-utils/lib/utils/markdown-transform.ts index 9949d42fb..8c1ad7037 100644 --- a/packages/url-utils/lib/utils/markdown-transform.ts +++ b/packages/url-utils/lib/utils/markdown-transform.ts @@ -114,4 +114,4 @@ function markdownTransform(markdown = '', siteUrl: string, transformFunctions: T return result; } -export = markdownTransform; +export default markdownTransform; diff --git a/packages/url-utils/lib/utils/mobiledoc-absolute-to-relative.ts b/packages/url-utils/lib/utils/mobiledoc-absolute-to-relative.ts index 58d8d11db..8374e111f 100644 --- a/packages/url-utils/lib/utils/mobiledoc-absolute-to-relative.ts +++ b/packages/url-utils/lib/utils/mobiledoc-absolute-to-relative.ts @@ -1,5 +1,5 @@ import absoluteToRelative from './absolute-to-relative'; -import mobiledocTransform = require('./mobiledoc-transform'); +import mobiledocTransform from './mobiledoc-transform'; interface MobiledocAbsoluteToRelativeOptions { assetsOnly?: boolean; @@ -19,4 +19,4 @@ function mobiledocAbsoluteToRelative(serializedMobiledoc: string, siteUrl: strin return mobiledocTransform(serializedMobiledoc, siteUrl, transformFunction, null, options); } -export = mobiledocAbsoluteToRelative; +export default mobiledocAbsoluteToRelative; diff --git a/packages/url-utils/lib/utils/mobiledoc-absolute-to-transform-ready.ts b/packages/url-utils/lib/utils/mobiledoc-absolute-to-transform-ready.ts index fcce2bea1..9293fd655 100644 --- a/packages/url-utils/lib/utils/mobiledoc-absolute-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/mobiledoc-absolute-to-transform-ready.ts @@ -1,5 +1,5 @@ import absoluteToTransformReady from './absolute-to-transform-ready'; -import mobiledocTransform = require('./mobiledoc-transform'); +import mobiledocTransform from './mobiledoc-transform'; interface MobiledocAbsoluteToTransformReadyOptions { assetsOnly?: boolean; @@ -19,4 +19,4 @@ function mobiledocAbsoluteToTransformReady(serializedMobiledoc: string, siteUrl: return mobiledocTransform(serializedMobiledoc, siteUrl, transformFunction, null, options); } -export = mobiledocAbsoluteToTransformReady; +export default mobiledocAbsoluteToTransformReady; diff --git a/packages/url-utils/lib/utils/mobiledoc-relative-to-absolute.ts b/packages/url-utils/lib/utils/mobiledoc-relative-to-absolute.ts index 93fb305c8..b01f1d1d7 100644 --- a/packages/url-utils/lib/utils/mobiledoc-relative-to-absolute.ts +++ b/packages/url-utils/lib/utils/mobiledoc-relative-to-absolute.ts @@ -1,5 +1,5 @@ import relativeToAbsolute from './relative-to-absolute'; -import mobiledocTransform = require('./mobiledoc-transform'); +import mobiledocTransform from './mobiledoc-transform'; interface MobiledocRelativeToAbsoluteOptions { assetsOnly?: boolean; @@ -15,4 +15,4 @@ function mobiledocRelativeToAbsolute(serializedMobiledoc: string, siteUrl: strin return mobiledocTransform(serializedMobiledoc, siteUrl, relativeToAbsolute, itemPath, options); } -export = mobiledocRelativeToAbsolute; +export default mobiledocRelativeToAbsolute; diff --git a/packages/url-utils/lib/utils/mobiledoc-relative-to-transform-ready.ts b/packages/url-utils/lib/utils/mobiledoc-relative-to-transform-ready.ts index 521485896..c9c14aa03 100644 --- a/packages/url-utils/lib/utils/mobiledoc-relative-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/mobiledoc-relative-to-transform-ready.ts @@ -1,5 +1,5 @@ import relativeToTransformReady from './relative-to-transform-ready'; -import mobiledocTransform = require('./mobiledoc-transform'); +import mobiledocTransform from './mobiledoc-transform'; interface MobiledocRelativeToTransformReadyOptions { assetsOnly?: boolean; @@ -15,4 +15,4 @@ function mobiledocRelativeToTransformReady(serializedMobiledoc: string, siteUrl: return mobiledocTransform(serializedMobiledoc, siteUrl, relativeToTransformReady, itemPath, options); } -export = mobiledocRelativeToTransformReady; +export default mobiledocRelativeToTransformReady; diff --git a/packages/url-utils/lib/utils/mobiledoc-to-transform-ready.ts b/packages/url-utils/lib/utils/mobiledoc-to-transform-ready.ts index da8739066..49b04733e 100644 --- a/packages/url-utils/lib/utils/mobiledoc-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/mobiledoc-to-transform-ready.ts @@ -1,5 +1,5 @@ -import mobiledocRelativeToAbsolute = require('./mobiledoc-relative-to-absolute'); -import mobiledocAbsoluteToTransformReady = require('./mobiledoc-absolute-to-transform-ready'); +import mobiledocRelativeToAbsolute from './mobiledoc-relative-to-absolute'; +import mobiledocAbsoluteToTransformReady from './mobiledoc-absolute-to-transform-ready'; interface MobiledocToTransformReadyOptions { assetsOnly?: boolean; @@ -21,4 +21,4 @@ function mobiledocToTransformReady(mobiledoc: string, siteUrl: string, itemPath? return mobiledocAbsoluteToTransformReady(absolute, siteUrl, actualOptions); } -export = mobiledocToTransformReady; +export default mobiledocToTransformReady; diff --git a/packages/url-utils/lib/utils/mobiledoc-transform.ts b/packages/url-utils/lib/utils/mobiledoc-transform.ts index 690919178..bbdd0b5f3 100644 --- a/packages/url-utils/lib/utils/mobiledoc-transform.ts +++ b/packages/url-utils/lib/utils/mobiledoc-transform.ts @@ -66,4 +66,4 @@ function mobiledocTransform(serializedMobiledoc: string, siteUrl: string, transf return JSON.stringify(mobiledoc); } -export = mobiledocTransform; +export default mobiledocTransform; diff --git a/packages/url-utils/lib/utils/plaintext-to-transform-ready.ts b/packages/url-utils/lib/utils/plaintext-to-transform-ready.ts index 83b2a8508..a5b082fb9 100644 --- a/packages/url-utils/lib/utils/plaintext-to-transform-ready.ts +++ b/packages/url-utils/lib/utils/plaintext-to-transform-ready.ts @@ -19,4 +19,4 @@ function plaintextToTransformReady(plaintext: string, siteUrl: string, itemPath? return plaintextAbsoluteToTransformReady(relativeTransformed, siteUrl, options); } -export = plaintextToTransformReady; +export default plaintextToTransformReady; diff --git a/packages/url-utils/lib/utils/relative-to-absolute.ts b/packages/url-utils/lib/utils/relative-to-absolute.ts index 2985df951..3b33c6561 100644 --- a/packages/url-utils/lib/utils/relative-to-absolute.ts +++ b/packages/url-utils/lib/utils/relative-to-absolute.ts @@ -1,6 +1,6 @@ // require the whatwg compatible URL library (same behaviour in node and browser) import {URL} from 'url'; -import urlJoin = require('./url-join'); +import urlJoin from './url-join'; // 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 diff --git a/packages/url-utils/lib/utils/replace-permalink.ts b/packages/url-utils/lib/utils/replace-permalink.ts index 9a21e7e62..6e5524240 100644 --- a/packages/url-utils/lib/utils/replace-permalink.ts +++ b/packages/url-utils/lib/utils/replace-permalink.ts @@ -1,4 +1,4 @@ -import moment = require('moment-timezone'); +import moment from 'moment-timezone'; interface Resource { published_at?: string | Date; @@ -56,4 +56,4 @@ function replacePermalink(permalink: string, resource: Resource, timezone = 'UTC }); } -export = replacePermalink; +export default replacePermalink; diff --git a/packages/url-utils/lib/utils/strip-subdirectory-from-path.ts b/packages/url-utils/lib/utils/strip-subdirectory-from-path.ts index 3fdbdc68d..45f6b2bc7 100644 --- a/packages/url-utils/lib/utils/strip-subdirectory-from-path.ts +++ b/packages/url-utils/lib/utils/strip-subdirectory-from-path.ts @@ -33,4 +33,4 @@ const stripSubdirectoryFromPath = function stripSubdirectoryFromPath(path = '', return path; }; -export = stripSubdirectoryFromPath; +export default stripSubdirectoryFromPath; diff --git a/packages/url-utils/lib/utils/to-transform-ready.ts b/packages/url-utils/lib/utils/to-transform-ready.ts index 02a32a1bf..e8c937364 100644 --- a/packages/url-utils/lib/utils/to-transform-ready.ts +++ b/packages/url-utils/lib/utils/to-transform-ready.ts @@ -18,4 +18,4 @@ function toTransformReady(url: string, siteUrl: string, itemPath?: string | ToTr return absoluteToTransformReady(absoluteUrl, siteUrl, options); } -export = toTransformReady; +export default toTransformReady; diff --git a/packages/url-utils/lib/utils/url-join.ts b/packages/url-utils/lib/utils/url-join.ts index dee270105..6624b8d47 100644 --- a/packages/url-utils/lib/utils/url-join.ts +++ b/packages/url-utils/lib/utils/url-join.ts @@ -1,4 +1,4 @@ -import deduplicateSubdirectory = require('./deduplicate-subdirectory'); +import deduplicateSubdirectory from './deduplicate-subdirectory'; interface UrlJoinOptions { rootUrl: string; @@ -38,4 +38,4 @@ function urlJoin(parts: string[], options: UrlJoinOptions): string { return deduplicateSubdirectory(url, options.rootUrl); } -export = urlJoin; +export default urlJoin; From 4939d73e3de6bf88d339445b8fc40b635bb22e4f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Oct 2025 08:23:39 +0000 Subject: [PATCH 14/14] fix(url-utils): Fix ESLint configuration for CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add .eslintignore to exclude dist/ directory from linting - Disable no-dupe-class-members for TypeScript (method overloads) - Disable filename convention rules for TypeScript files These rules were causing CI failures because: 1. TypeScript compiler output in dist/ doesn't follow linting rules 2. TypeScript method overloads are flagged as duplicate class members 3. TypeScript files use different naming conventions than JS files Linting now passes, all tests passing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- packages/url-utils/.eslintignore | 4 ++++ packages/url-utils/.eslintrc.js | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 packages/url-utils/.eslintignore diff --git a/packages/url-utils/.eslintignore b/packages/url-utils/.eslintignore new file mode 100644 index 000000000..a66d7a1fc --- /dev/null +++ b/packages/url-utils/.eslintignore @@ -0,0 +1,4 @@ +dist/ +node_modules/ +coverage/ +.nyc_output/ diff --git a/packages/url-utils/.eslintrc.js b/packages/url-utils/.eslintrc.js index 17fb214aa..18dc69461 100644 --- a/packages/url-utils/.eslintrc.js +++ b/packages/url-utils/.eslintrc.js @@ -14,7 +14,12 @@ module.exports = { rules: { // Disable rules that conflict with TypeScript 'no-unused-vars': 'off', - 'no-undef': 'off' + 'no-undef': 'off', + // TypeScript supports method overloads which ESLint sees as duplicates + 'no-dupe-class-members': 'off', + // TypeScript files use PascalCase for classes and kebab-case for filenames + 'ghost/filenames/match-regex': 'off', + 'ghost/filenames/match-exported-class': 'off' } } ]