@zeropress/build-core 0.1.0 → 0.1.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeropress/build-core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Shared ZeroPress build and partial-render core",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -158,10 +158,11 @@ async function finalizeBuildResult(writer, summaries, options) {
158
158
  }
159
159
 
160
160
  async function renderRoute(state, templateName, route) {
161
+ const currentUrl = normalizeRoutePath(route.path);
161
162
  let html = await state.engine.render(
162
163
  templateName,
163
164
  { ...route },
164
- createRenderContext(state.previewData.site, route.path),
165
+ createRenderContext(state.previewData.site, currentUrl),
165
166
  );
166
167
  html = state.assetProcessor.updateAssetReferences(html, state.assetMap);
167
168
  await writeOutput(state.writer, state.summaries, routePathToOutputPath(route.path), html, 'text/html');
@@ -305,7 +306,8 @@ function normalizeRoutePath(routePath) {
305
306
  if (!routePath || routePath === '/') {
306
307
  return '/';
307
308
  }
308
- return `/${String(routePath).replace(/^\/+|\/+$/g, '')}/`;
309
+ const normalized = decodeRoutePath(String(routePath)).replace(/^\/+|\/+$/g, '');
310
+ return `/${normalized}/`;
309
311
  }
310
312
 
311
313
  function normalizeOutputPath(filePath) {
@@ -356,7 +358,7 @@ function buildSitemapXml(previewData) {
356
358
  ];
357
359
 
358
360
  const body = entries.map((entry) => {
359
- const loc = escapeXml(new URL(entry.url, previewData.site.url).toString());
361
+ const loc = escapeXml(resolveSiteUrl(previewData.site.url, entry.url));
360
362
  const lastmod = entry.lastmod.toISOString().split('T')[0];
361
363
  return ` <url>\n <loc>${loc}</loc>\n <lastmod>${lastmod}</lastmod>\n <changefreq>${entry.changefreq}</changefreq>\n <priority>${entry.priority.toFixed(1)}</priority>\n </url>`;
362
364
  }).join('\n');
@@ -369,7 +371,7 @@ function buildFeedXml(previewData) {
369
371
  .sort((a, b) => toDate(b.published_at_iso).getTime() - toDate(a.published_at_iso).getTime())
370
372
  .slice(0, 20)
371
373
  .map((post) => {
372
- const url = new URL(`/posts/${encodeSlugSegment(post.slug)}/`, previewData.site.url).toString();
374
+ const url = resolveSiteUrl(previewData.site.url, `/posts/${encodeSlugSegment(post.slug)}/`);
373
375
  return ` <item>\n <title>${escapeXml(post.title)}</title>\n <link>${escapeXml(url)}</link>\n <guid>${escapeXml(url)}</guid>\n <pubDate>${toDate(post.published_at_iso).toUTCString()}</pubDate>\n <description>${escapeXml(post.excerpt)}</description>\n </item>`;
374
376
  })
375
377
  .join('\n');
@@ -438,7 +440,36 @@ function getContentType(assetPath) {
438
440
  }
439
441
 
440
442
  function encodeSlugSegment(slug) {
441
- return encodeURIComponent(String(slug));
443
+ return normalizeStoredSlug(slug);
444
+ }
445
+
446
+ function normalizeStoredSlug(slug) {
447
+ if (typeof slug !== 'string') {
448
+ return '';
449
+ }
450
+
451
+ const trimmed = slug.trim();
452
+ if (!trimmed.includes('%')) {
453
+ return trimmed;
454
+ }
455
+
456
+ try {
457
+ return decodeURIComponent(trimmed);
458
+ } catch {
459
+ return trimmed;
460
+ }
461
+ }
462
+
463
+ function decodeRoutePath(routePath) {
464
+ try {
465
+ return decodeURI(routePath);
466
+ } catch {
467
+ return routePath;
468
+ }
469
+ }
470
+
471
+ function resolveSiteUrl(siteUrl, relativePath) {
472
+ return decodeURI(new URL(relativePath, siteUrl).toString());
442
473
  }
443
474
 
444
475
  function toDate(value) {