{"record":{"id":"be83482cd959ecfc","repo":"coding-horror/basic-computer-games","slug":"unknown-file-type-found-file","errorCode":null,"errorMessage":"Unknown file-type found: ${file}","messagePattern":"Unknown file-type found: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"00_Utilities/build-index.js","lineNumber":33,"sourceCode":"const JAVASCRIPT_FOLDER = 'javascript';\nconst IGNORE_FOLDERS_START_WITH = ['.', '00_', 'buildJvm', 'Sudoku'];\nconst IGNORE_FILES = [\n\t// \"84 Super Star Trek\"  has it's own node/js implementation (using xterm)\n\t'cli.mjs', 'superstartrek.mjs'\n];\n\nfunction createGameLinks(game) {\n\tconst creatFileLink = (file, name = path.basename(file)) => {\n\t\tif (file.endsWith('.html')) {\n\t\t\treturn `\n\t\t\t\t<li><a href=\"${file}\">${name.replace('.html', '')}</a></li>\n\t\t\t`;\n\t\t} else if (file.endsWith('.mjs')) {\n\t\t\treturn `\n\t\t\t\t<li><a href=\"./00_Common/javascript/WebTerminal/terminal.html#${file}\">${name.replace('.mjs', '')} (node.js)</a></li>\n\t\t\t`;\n\t\t} else {\n\t\t\tthrow new Error(`Unknown file-type found: ${file}`);\n\t\t}\n\t}\n\n\tif (game.files.length > 1) {\n\t\tconst entries = game.files.map(file => {\n\t\t\treturn creatFileLink(file);\n\t\t});\n\t\treturn `\n\t\t\t<li>\n\t\t\t\t<span>${game.name}</span>\n\t\t\t\t<ul>${entries.map(e => `\\t\\t\\t${e}`).join('\\n')}</ul>\n\t\t\t</li>\n\t\t`;\n\t} else {\n\t\treturn creatFileLink(game.files[0], game.name);\n\t}\n}\n","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/coding-horror/basic-computer-games/blob/5301155192d91d74d337899cecc59dbda59c4c17/00_Utilities/build-index.js#L15-L51","documentation":"Thrown by createFileLink() in the build-index.js index generator when a file path passed to it ends with neither '.html' nor '.mjs'. The generator only knows how to render links for those two file kinds, so any other extension is treated as a programmer error. In practice findJSFilesInFolder() upstream filters to only .html/.mjs, so this branch is a defensive guard that is effectively unreachable through the normal pipeline unless a new extension is added to the filter without updating the link builder.","triggerScenarios":"Calling createGameLinks(game) where game.files contains an entry whose extension is not .html or .mjs; e.g. someone edits findJSFilesInFolder to also collect '.js' files but forgets to teach createFileLink how to link them, or invokes createFileLink directly with an arbitrary path.","commonSituations":"Extending the index builder to support a new file type (e.g. plain .js or .ts web ports) and adding the extension to the filter array at build-index.js:100-101 without adding a matching branch in createFileLink at line 23-34.","solutions":["Add a matching else-if branch in createFileLink for the new extension before the final else, mirroring the .html/.mjs branches.","If the new type should be ignored, add it to IGNORE_FILES at line 17 instead of collecting it.","Revert the upstream filter change so only .html/.mjs are collected."],"exampleFix":"// before\nconst mjsFiles = files.filter(file => file.endsWith('.mjs'));\nconst entries = [...htmlFiles, ...mjsFiles].filter(...);\n// createFileLink has no case for .js -> throws\n\n// after (add branch)\n} else if (file.endsWith('.js')) {\n  return `\\n\\t\\t\\t<li><a href=\"./00_Common/javascript/WebTerminal/terminal.html#${file}\">${name.replace('.js','')} (node.js)</a></li>\\n\\t\\t`;\n}","handlingStrategy":"validation","validationCode":"// Validate game.files before calling createGameLinks\nfunction assertKnownFiles(files) {\n  const bad = files.filter(f => !f.endsWith('.html') && !f.endsWith('.mjs'));\n  if (bad.length) throw new Error(`Unsupported extensions: ${bad.join(', ')}`);\n}\n// in createGameLinks:\nassertKnownFiles(game.files);","typeGuard":"// Node has no static type guard; runtime check instead\nconst isLinkableFile = (f) => typeof f === 'string' && (f.endsWith('.html') || f.endsWith('.mjs'));","tryCatchPattern":"// main() already wraps findJSFilesInFolder in try/catch (build-index.js:134-139);\n// wrap createIndexHtml similarly if createGameLinks can throw:\ntry { const html = createIndexHtml(TITLE, games); }\ncatch (e) { console.error('Index build failed:', e.message); process.exit(1); }","preventionTips":["When adding a new supported extension to findJSFilesInFolder's filter, add the matching branch in createFileLink in the same commit.","Keep a single constant (e.g. SUPPORTED_EXT) referenced by both the filter and the link builder so they cannot drift.","Add a unit test asserting createFileLink handles every extension the filter collects."],"tags":["nodejs","build-script","file-type","index-generator"],"backgroundTag":null,"analyzedSha":"5301155192d91d74d337899cecc59dbda59c4c17","analyzedAt":"2026-08-13T19:29:00.979Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}