{"record":{"id":"1ebde02338533fc5","repo":"jamiebuilds/the-super-tiny-compiler","slug":"node-type","errorCode":null,"errorMessage":"node.type","messagePattern":"node\\.type","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"the-super-tiny-compiler.js","lineNumber":794,"sourceCode":"      case 'Program':\n        traverseArray(node.body, node);\n        break;\n\n      // Next we do the same with `CallExpression` and traverse their `params`.\n      case 'CallExpression':\n        traverseArray(node.params, node);\n        break;\n\n      // In the cases of `NumberLiteral` and `StringLiteral` we don't have any\n      // child nodes to visit, so we'll just break.\n      case 'NumberLiteral':\n      case 'StringLiteral':\n        break;\n\n      // And again, if we haven't recognized the node type then we'll throw an\n      // error.\n      default:\n        throw new TypeError(node.type);\n    }\n\n    // If there is an `exit` method for this node type we'll call it with the\n    // `node` and its `parent`.\n    if (methods && methods.exit) {\n      methods.exit(node, parent);\n    }\n  }\n\n  // Finally we kickstart the traverser by calling `traverseNode` with our ast\n  // with no `parent` because the top level of the AST doesn't have a parent.\n  traverseNode(ast, null);\n}\n\n/**\n * ============================================================================\n *                                   ⁽(◍˃̵͈̑ᴗ˂̵͈̑)⁽\n *                              THE TRANSFORMER!!!","sourceCodeStart":776,"sourceCodeEnd":812,"githubUrl":"https://github.com/jamiebuilds/the-super-tiny-compiler/blob/d8d40130459d1537f6117a927947cd46c83182b0/the-super-tiny-compiler.js#L776-L812","documentation":"traverseNode's visitor switch throws the node's type string when no case matches and there is no visitor method for that type. Out of the box the traverser handles 'NumberLiteral', 'CallExpression', and 'StringLiteral' (plus 'Program' handled specially). Any other node type in the AST — including nodes produced by a transformer or a custom parser — triggers this default throw with the node type as the message.","triggerScenarios":"Calling traverser(ast, visitor) on an AST containing node types other than Program/NumberLiteral/CallExpression/StringLiteral, unless the supplied visitor object has an enter/exit method keyed by that type (in which case the switch is skipped). Common with custom ASTs or transforms that add node types like 'Identifier' or 'OperatorLiteral'.","commonSituations":"Reusing the traverser with a custom AST from a different parser. Extending the compiler with new node types but forgetting to add cases or visitor methods. A transformer mutating node.type between enter and exit, or a previous plugin renaming types incompatibly.","solutions":["Add a visitor method for the offending node type in the visitor object you pass to traverser() (e.g. visitor['Identifier'] = { enter() {} }) — the existing-method check runs before the switch.","If maintaining a fork, add a case for the node type in traverseNode's switch before default.","Verify the AST actually came from the bundled parser() and no transformer altered node.type values.","If the node type is invalid, fix the upstream producer (parser or transformer) instead of the traverser."],"exampleFix":"// before\ntraverser(ast, {}); // ast contains { type: 'Identifier' } -> throws TypeError: Identifier\n\n// after\ntraverser(ast, {\n  Identifier: {\n    enter(node, parent) { /* handle or ignore */ }\n  }\n});","handlingStrategy":"validation","validationCode":"const KNOWN = new Set(['Program','NumberLiteral','CallExpression','StringLiteral']);\nfunction astIsTraversable(node, ok = true) {\n  if (!node || typeof node.type !== 'string') return false;\n  return KNOWN.has(node.type) && (node.body ? node.body.every(n => astIsTraversable(n)) : true);\n}\nif (!astIsTraversable(ast)) throw new Error('AST contains unsupported node types');\ntraverser(ast, visitor);","typeGuard":"function isKnownNodeType(node) {\n  return node != null && typeof node.type === 'string' && ['Program','NumberLiteral','CallExpression','StringLiteral'].includes(node.type);\n}","tryCatchPattern":"try { traverser(ast, visitor); } catch (e) { if (e instanceof TypeError && !['Program','NumberLiteral','CallExpression','StringLiteral'].includes(e.message)) { /* unknown node type: e.message; add visitor[e.message] or skip */ } else throw e; }","preventionTips":["Declare an enter (or exit) method for every custom node type you introduce; the traverser calls it before the switch.","Keep parser, traverser, and transformer changes in sync when adding node types.","Run a quick AST type scan before traversing third-party ASTs."],"tags":["traverser","visitor","ast","unknown-node-type"],"backgroundTag":"unknown-ast-node-type","analyzedSha":"d8d40130459d1537f6117a927947cd46c83182b0","analyzedAt":"2026-08-28T20:32:54.726Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}