@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
JavaScript
"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