@wdprlib/render 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -4294,7 +4294,7 @@ var SANITIZE_CONFIG = {
4294
4294
  "width"
4295
4295
  ]
4296
4296
  },
4297
- allowedSchemes: ["https"]
4297
+ allowedSchemes: ["https", "http"]
4298
4298
  };
4299
4299
  function findIframes(html) {
4300
4300
  const doc = import_htmlparser2.parseDocument(html);
@@ -4342,7 +4342,7 @@ function matchesAllowlistEntry(url, entry) {
4342
4342
  }
4343
4343
  return true;
4344
4344
  }
4345
- function validateAndSanitizeEmbed(content, allowlist) {
4345
+ function validateAndSanitizeEmbed(content, allowlist, baseUrl) {
4346
4346
  const sanitized = import_sanitize_html.default(content.trim(), SANITIZE_CONFIG);
4347
4347
  if (!sanitized.trim()) {
4348
4348
  return null;
@@ -4358,11 +4358,16 @@ function validateAndSanitizeEmbed(content, allowlist) {
4358
4358
  }
4359
4359
  let url;
4360
4360
  try {
4361
- url = new URL(src);
4361
+ if (src.startsWith("//")) {
4362
+ const base = baseUrl ?? "https://localhost";
4363
+ url = new URL(src, base);
4364
+ } else {
4365
+ url = new URL(src);
4366
+ }
4362
4367
  } catch {
4363
4368
  return null;
4364
4369
  }
4365
- if (url.protocol !== "https:") {
4370
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
4366
4371
  return null;
4367
4372
  }
4368
4373
  if (allowlist !== null) {
@@ -4385,7 +4390,7 @@ function normalizeBooleanAttributes(html) {
4385
4390
  }
4386
4391
  function renderEmbedBlock(ctx, data) {
4387
4392
  const allowlist = ctx.options.embedAllowlist !== undefined ? ctx.options.embedAllowlist : DEFAULT_EMBED_ALLOWLIST;
4388
- const sanitized = validateAndSanitizeEmbed(data.contents, allowlist);
4393
+ const sanitized = validateAndSanitizeEmbed(data.contents, allowlist, ctx.options.baseUrl);
4389
4394
  if (sanitized === null) {
4390
4395
  ctx.push('<div class="error-block">Sorry, no match for the embedded content.</div>');
4391
4396
  return;
package/dist/index.d.cts CHANGED
@@ -70,6 +70,13 @@ interface RenderResolvers {
70
70
  * Options for HTML rendering
71
71
  */
72
72
  interface RenderOptions {
73
+ /**
74
+ * Base URL used to resolve protocol-relative URLs (e.g., "//example.com/path").
75
+ * The protocol of this URL is inherited by protocol-relative references.
76
+ * Example: "https://scp-wiki.wikidot.com" or "http://scp-jp.wikidot.com"
77
+ * If not provided, protocol-relative URLs default to HTTPS.
78
+ */
79
+ baseUrl?: string;
73
80
  /** Wikitext settings controlling rendering behavior */
74
81
  settings?: WikitextSettings;
75
82
  /** Page context for resolving file paths, links, etc. */
package/dist/index.d.ts CHANGED
@@ -70,6 +70,13 @@ interface RenderResolvers {
70
70
  * Options for HTML rendering
71
71
  */
72
72
  interface RenderOptions {
73
+ /**
74
+ * Base URL used to resolve protocol-relative URLs (e.g., "//example.com/path").
75
+ * The protocol of this URL is inherited by protocol-relative references.
76
+ * Example: "https://scp-wiki.wikidot.com" or "http://scp-jp.wikidot.com"
77
+ * If not provided, protocol-relative URLs default to HTTPS.
78
+ */
79
+ baseUrl?: string;
73
80
  /** Wikitext settings controlling rendering behavior */
74
81
  settings?: WikitextSettings;
75
82
  /** Page context for resolving file paths, links, etc. */
package/dist/index.js CHANGED
@@ -4242,7 +4242,7 @@ var SANITIZE_CONFIG = {
4242
4242
  "width"
4243
4243
  ]
4244
4244
  },
4245
- allowedSchemes: ["https"]
4245
+ allowedSchemes: ["https", "http"]
4246
4246
  };
4247
4247
  function findIframes(html) {
4248
4248
  const doc = parseDocument(html);
@@ -4290,7 +4290,7 @@ function matchesAllowlistEntry(url, entry) {
4290
4290
  }
4291
4291
  return true;
4292
4292
  }
4293
- function validateAndSanitizeEmbed(content, allowlist) {
4293
+ function validateAndSanitizeEmbed(content, allowlist, baseUrl) {
4294
4294
  const sanitized = sanitizeHtml(content.trim(), SANITIZE_CONFIG);
4295
4295
  if (!sanitized.trim()) {
4296
4296
  return null;
@@ -4306,11 +4306,16 @@ function validateAndSanitizeEmbed(content, allowlist) {
4306
4306
  }
4307
4307
  let url;
4308
4308
  try {
4309
- url = new URL(src);
4309
+ if (src.startsWith("//")) {
4310
+ const base = baseUrl ?? "https://localhost";
4311
+ url = new URL(src, base);
4312
+ } else {
4313
+ url = new URL(src);
4314
+ }
4310
4315
  } catch {
4311
4316
  return null;
4312
4317
  }
4313
- if (url.protocol !== "https:") {
4318
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
4314
4319
  return null;
4315
4320
  }
4316
4321
  if (allowlist !== null) {
@@ -4333,7 +4338,7 @@ function normalizeBooleanAttributes(html) {
4333
4338
  }
4334
4339
  function renderEmbedBlock(ctx, data) {
4335
4340
  const allowlist = ctx.options.embedAllowlist !== undefined ? ctx.options.embedAllowlist : DEFAULT_EMBED_ALLOWLIST;
4336
- const sanitized = validateAndSanitizeEmbed(data.contents, allowlist);
4341
+ const sanitized = validateAndSanitizeEmbed(data.contents, allowlist, ctx.options.baseUrl);
4337
4342
  if (sanitized === null) {
4338
4343
  ctx.push('<div class="error-block">Sorry, no match for the embedded content.</div>');
4339
4344
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdprlib/render",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "HTML renderer for Wikidot markup",
5
5
  "keywords": [
6
6
  "html",