UNPKG

@mdfriday/foundry

Version:

The core engine of MDFriday. Convert Markdown and shortcodes into fully themed static sites – Hugo-style, powered by TypeScript.

200 lines 6.81 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseURL = void 0; class BaseURL { constructor(url, isRelative = false) { this.url = url; this.isRelative = isRelative; this.withPath = url.toString(); this.withPathNoTrailingSlash = this.withPath.replace(/\/$/, ''); if (isRelative) { this.withoutPath = '/'; } else { const urlNoPath = new URL(url.toString()); urlNoPath.pathname = ''; // Remove trailing slash from withoutPath this.withoutPath = urlNoPath.toString().replace(/\/$/, ''); } this.basePath = url.pathname; this.basePathNoTrailingSlash = this.basePath.replace(/\/$/, ''); } /** * Creates a new BaseURL instance from a string. * Supports various formats: * - Absolute URLs: https://example.com/, https://example.com/public/ * - Relative paths: /public/, / * - Protocol-relative URLs: //example.com/ */ static fromString(baseUrl) { try { // Handle empty or just slash if (!baseUrl || baseUrl === '/') { baseUrl = '/'; } // Normalize the input const trimmed = baseUrl.trim(); // Check if it's a relative path (starts with / but not //) if (trimmed.startsWith('/') && !trimmed.startsWith('//')) { // This is a relative path, we need to create a full URL for the URL constructor // Use a dummy domain to create a valid URL object const dummyUrl = new URL(trimmed, 'http://localhost'); // Ensure trailing slash if (!dummyUrl.pathname.endsWith('/')) { dummyUrl.pathname += '/'; } return new BaseURL(dummyUrl, true); } // Check if it's a protocol-relative URL (starts with //) if (trimmed.startsWith('//')) { // Add a default protocol const fullUrl = 'https:' + trimmed; const url = new URL(fullUrl); if (!url.pathname.endsWith('/')) { url.pathname += '/'; } return new BaseURL(url); } // Check if it has a protocol if (trimmed.includes('://')) { const url = new URL(trimmed); // Validate supported protocols if (!['http:', 'https:'].includes(url.protocol)) { throw new Error(`Unsupported protocol: ${url.protocol}. Only http and https are supported.`); } // Ensure trailing slash if (!url.pathname.endsWith('/')) { url.pathname += '/'; } return new BaseURL(url); } // Check if it looks like a scheme: format (e.g., mailto:) if (trimmed.includes(':') && !trimmed.includes('/')) { const colonIndex = trimmed.indexOf(':'); const scheme = trimmed.substring(0, colonIndex + 1); throw new Error(`Unsupported protocol: ${scheme}. Only http and https are supported.`); } // If no protocol, assume it's a domain name and default to https const url = new URL('https://' + trimmed); if (!url.pathname.endsWith('/')) { url.pathname += '/'; } return new BaseURL(url); } catch (err) { throw new Error(`Invalid URL: ${err?.message || 'Unknown error'}`); } } /** * Returns the appropriate root URL based on the path. */ getRoot(path) { if (this.isRelative) { // For relative base URLs, always return the path part return this.basePath; } if (path.startsWith('/')) { // Treat it as relative to the server root return this.withoutPath; } // Treat it as relative to the baseURL return this.withPath; } toString() { if (this.isRelative) { return this.basePath; } return this.withPath; } path() { return this.url.pathname; } port() { return this.url.port ? parseInt(this.url.port) : 0; } /** * Returns the URL to the host root without any path elements. */ hostURL() { if (this.isRelative) { return '/'; } return this.toString().replace(this.path(), ''); } /** * Returns the protocol (scheme) of the URL. */ protocol() { return this.url.protocol; } /** * Returns the host (hostname + port) of the URL. */ host() { return this.url.host; } /** * Returns the hostname of the URL. */ hostname() { return this.url.hostname; } /** * Returns a copy of the internal URL. * The copy can be safely used and modified. */ getURL() { return new URL(this.url.toString()); } /** * Returns the BaseURL prefixed with the given protocol. * The Protocol is normally of the form "scheme://", i.e. "webcal://". */ withProtocol(protocol) { if (this.isRelative) { throw new Error('Cannot change protocol of relative URL'); } const u = this.getURL(); let scheme = protocol; const isFullProtocol = scheme.endsWith('://'); const isOpaqueProtocol = scheme.endsWith(':'); if (isFullProtocol) { scheme = scheme.slice(0, -3); } else if (isOpaqueProtocol) { scheme = scheme.slice(0, -1); } // In TypeScript/JavaScript, URL doesn't support opaque URLs directly // We'll need to handle this differently than in Go if (isOpaqueProtocol && !u.pathname) { throw new Error(`cannot determine BaseURL for protocol ${protocol}`); } u.protocol = scheme; return BaseURL.fromString(u.toString()); } /** * Returns a new BaseURL with the specified port. */ withPort(port) { if (this.isRelative) { throw new Error('Cannot set port on relative URL'); } const u = this.getURL(); u.port = port.toString(); return BaseURL.fromString(u.toString()); } /** * Checks if this BaseURL is relative (path-only). */ isRelativeURL() { return this.isRelative; } /** * Checks if this BaseURL is absolute (has protocol and host). */ isAbsoluteURL() { return !this.isRelative; } } exports.BaseURL = BaseURL; //# sourceMappingURL=baseurl.js.map