@kenjura/ursa 0.34.0 → 0.39.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/CHANGELOG.md CHANGED
@@ -1,3 +1,30 @@
1
+ # 0.39.0
2
+ 2025-12-13
3
+
4
+ - Updated to node 24.5 to satisfy npm Trusted Publishing
5
+ - Refactored Github Actions
6
+ - Added CONTRIBUTING.md
7
+
8
+ # 0.38.0
9
+ 2025-12-13
10
+
11
+ - Updated Github Actions workflow to use OIDC for authentication
12
+
13
+ # 0.37.0
14
+ 2025-12-13
15
+
16
+ - Added Github Actions workflow for CI/CD (npm publish)
17
+
18
+ # 0.36.0
19
+ 2025-12-13
20
+
21
+ - Links to a valid .md file in source will now render as a link to the corresponding .html file (and show as an active link)
22
+
23
+ # 0.35.0
24
+ 2025-12-11
25
+
26
+ - Fixed issue where directory indices were empty
27
+
1
28
  # 0.34.0
2
29
  2025-12-11
3
30
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@kenjura/ursa",
3
3
  "author": "Andrew London <andrew@kenjura.com>",
4
4
  "type": "module",
5
- "version": "0.34.0",
5
+ "version": "0.39.0",
6
6
  "description": "static site generator from MD/wikitext/YML",
7
7
  "main": "lib/index.js",
8
8
  "bin": {
@@ -157,7 +157,24 @@ function resolveHref(href, validPaths, currentDocPath = null) {
157
157
  // Check if the href already has an extension
158
158
  const ext = extname(hrefWithoutHash);
159
159
  if (ext) {
160
- // Has extension but doesn't exist
160
+ // Special handling for .md links - convert to .html if valid
161
+ if (ext.toLowerCase() === '.md') {
162
+ // Remove .md and check if .html version exists
163
+ const pathWithoutMd = normalized.slice(0, -3); // Remove '.md'
164
+ const htmlPath = pathWithoutMd + '.html';
165
+ debugTries.push(`${normalized} (.md → .html) ${htmlPath} → ${validPaths.has(htmlPath) ? '✓' : '✗'}`);
166
+ if (validPaths.has(htmlPath)) {
167
+ // Convert .md to .html in the resolved href
168
+ const resolvedHref = absoluteHref.slice(0, -3) + '.html' + hash;
169
+ return { resolvedHref, inactive: false, debug: debugTries.join(' | ') };
170
+ }
171
+ // Also check without extension (in case valid paths don't have .html suffix)
172
+ if (validPaths.has(pathWithoutMd)) {
173
+ const resolvedHref = absoluteHref.slice(0, -3) + '.html' + hash;
174
+ return { resolvedHref, inactive: false, debug: debugTries.join(' | ') };
175
+ }
176
+ }
177
+ // Has extension but doesn't exist (or is not .md)
161
178
  debugTries.push(`${normalized} → ✗`);
162
179
  return { resolvedHref: absoluteHref + hash, inactive: true, debug: debugTries.join(' | ') };
163
180
  }
@@ -200,17 +200,42 @@ export async function generate({
200
200
  allSourceFilenamesThatAreArticles.map(async (file) => {
201
201
  try {
202
202
  const rawBody = await readFile(file, "utf8");
203
+ const type = parse(file).ext;
204
+ const ext = extname(file);
205
+ const base = basename(file, ext);
206
+ const dir = addTrailingSlash(dirname(file)).replace(source, "");
207
+
208
+ // Calculate output paths for this file
209
+ const outputFilename = file
210
+ .replace(source, output)
211
+ .replace(parse(file).ext, ".html");
212
+ const url = '/' + outputFilename.replace(output, '');
203
213
 
204
214
  // Skip files that haven't changed (unless --clean flag is set)
205
215
  if (!_clean && !needsRegeneration(file, rawBody, hashCache)) {
206
216
  skippedCount++;
207
- return; // Skip this file
217
+ // Still need to populate jsonCache for directory indices
218
+ const meta = extractMetadata(rawBody);
219
+ const body = renderFile({
220
+ fileContents: rawBody,
221
+ type,
222
+ dirname: dir,
223
+ basename: base,
224
+ });
225
+ jsonCache.set(file, {
226
+ name: base,
227
+ url,
228
+ contents: rawBody,
229
+ bodyHtml: body,
230
+ metadata: meta,
231
+ transformedMetadata: '',
232
+ });
233
+ return; // Skip regenerating this file
208
234
  }
209
235
 
210
236
  console.log(`processing article ${file}`);
211
237
  regeneratedCount++;
212
238
 
213
- const type = parse(file).ext;
214
239
  const meta = extractMetadata(rawBody);
215
240
  const rawMeta = extractRawMetadata(rawBody);
216
241
  const bodyLessMeta = rawMeta ? rawBody.replace(rawMeta, "") : rawBody;
@@ -218,9 +243,6 @@ export async function generate({
218
243
  dirname(file),
219
244
  meta
220
245
  );
221
- const ext = extname(file);
222
- const base = basename(file, ext);
223
- const dir = addTrailingSlash(dirname(file)).replace(source, "");
224
246
 
225
247
  // Calculate the document's URL path (e.g., "/character/index.html")
226
248
  const docUrlPath = '/' + dir + base + '.html';
@@ -269,10 +291,6 @@ export async function generate({
269
291
  // Pass docUrlPath so relative links can be resolved correctly
270
292
  finalHtml = markInactiveLinks(finalHtml, validPaths, docUrlPath, false);
271
293
 
272
- const outputFilename = file
273
- .replace(source, output)
274
- .replace(parse(file).ext, ".html");
275
-
276
294
  console.log(`writing article to ${outputFilename}`);
277
295
 
278
296
  await outputFile(outputFilename, finalHtml);
@@ -280,7 +298,6 @@ export async function generate({
280
298
  // json
281
299
 
282
300
  const jsonOutputFilename = outputFilename.replace(".html", ".json");
283
- const url = '/' + outputFilename.replace(output, '');
284
301
  const jsonObject = {
285
302
  name: base,
286
303
  url,