{"id":10619,"library":"character-parser","title":"Character Parser for Template Snippets","description":"`character-parser` is a focused JavaScript utility library designed for parsing JavaScript code snippets, particularly within template languages like EJS or Jade. Its primary function is to robustly handle bracket nesting, strings, and comments, allowing for the reliable extraction of delimited JavaScript sections without performing a full syntax validation or abstract syntax tree (AST) generation. The current stable version is 4.0.0, which introduced significant changes including native ES module support and updated package export configurations. This library differentiates itself by offering a lightweight, character-by-character parsing mechanism and state management, providing functions to parse entire strings or single characters, track nesting depth, and find code segments based on custom delimiters while intelligently ignoring content within nested structures or comments. It does not aim to be a comprehensive JavaScript parser but rather a precise tool for template-driven code extraction.","status":"active","version":"4.0.0","language":"javascript","source_language":"en","source_url":"https://github.com/ForbesLindesay/character-parser","tags":["javascript","parser","JavaScript","bracket","nesting","comment","string","escape","escaping","typescript"],"install":[{"cmd":"npm install character-parser","lang":"bash","label":"npm"},{"cmd":"yarn add character-parser","lang":"bash","label":"yarn"},{"cmd":"pnpm add character-parser","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"Since v4.0.0, the package primarily supports ES Modules. CommonJS require() is not officially supported via the package.json exports field for named exports.","wrong":"const parse = require('character-parser').parse","symbol":"parse","correct":"import { parse } from 'character-parser'"},{"note":"The v4.0.0 update introduced an 'exports' field in package.json, restricting imports to only the main entry point 'character-parser'. Direct imports of internal files are no longer supported.","wrong":"import parseUntil from 'character-parser/parseUntil'","symbol":"parseUntil","correct":"import { parseUntil } from 'character-parser'"},{"note":"TypeScript types are included, ensuring strong typing when used in TypeScript projects. ES module imports are the recommended way to use the library.","wrong":"const { defaultState } = require('character-parser')","symbol":"defaultState","correct":"import { defaultState } from 'character-parser'"}],"quickstart":{"code":"import { parseUntil, parse } from 'character-parser';\nimport assert from 'assert';\n\nconsole.log('--- Custom Delimited Expressions (EJS-style) ---');\n// Example 1: Parsing up to a custom delimiter (EJS-style)\nconst ejsSnippet = 'foo.bar(\"%>\\\").baz%> bing bong';\nconst section1 = parseUntil(ejsSnippet, '%>');\nassert.strictEqual(section1.start, 0);\nassert.strictEqual(section1.end, 18);\nassert.strictEqual(section1.src, 'foo.bar(\"%>\\\").baz');\nconsole.log(`Parsed section 1: \"${section1.src}\" (Start: ${section1.start}, End: ${section1.end})`);\n\nconst ejsSnippetOffset = '<%foo.bar(\"%>\\\").baz%> bing bong';\nconst section2 = parseUntil(ejsSnippetOffset, '%>', { start: 2 });\nassert.strictEqual(section2.start, 2);\nassert.strictEqual(section2.end, 20);\nassert.strictEqual(section2.src, 'foo.bar(\"%>\\\").baz');\nconsole.log(`Parsed section 2 with offset: \"${section2.src}\" (Start: ${section2.start}, End: ${section2.end})`);\n\nconsole.log('\\n--- Parsing Depth Changes ---');\n// Example 2: Parsing depth changes with state management\nlet state = parse('foo(arg1, arg2, {\\n  foo: [a, b\\n');\nconsole.log('Initial stack after first parse:', state.stack);\nassert.deepStrictEqual(state.stack, [')', '}', ']']);\n\nstate = parse('    c, d]\\n  })', state);\nconsole.log('Final stack after second parse:', state.stack);\nassert.deepStrictEqual(state.stack, []);\n\nconsole.log('\\nAll assertions passed!');","lang":"typescript","description":"This quickstart demonstrates how to use `character-parser` to find delimited expressions and manage parsing state across multiple string segments, including handling nested structures and escaped characters."},"warnings":[{"fix":"Migrate to TypeScript for type safety, or rely on custom Flow definitions if still using Flow.","message":"Version 4.0.0 removed official support for Flow types. While the library itself is written in TypeScript and ships with TypeScript types, Flow users will need to manage their own type definitions or downgrade.","severity":"breaking","affected_versions":">=4.0.0"},{"fix":"Ensure all imports are from the main package path: `import { NamedExport } from 'character-parser'`. Do not attempt to import from internal directories.","message":"The `package.json` now includes an `exports` field, which restricts available imports to only the main entry point (`'character-parser'`). Importing arbitrary internal files (e.g., `character-parser/lib/some-internal-file`) is no longer supported and will result in module resolution errors in environments that respect the `exports` field.","severity":"breaking","affected_versions":">=4.0.0"},{"fix":"Wrap parsing operations in `try...catch` blocks to gracefully handle and identify syntax errors. Inspect the `error.code` property for specific error types.","message":"All parsing methods (`parse`, `parseUntil`, `parseChar`) may throw exceptions in case of syntax errors (e.g., unclosed brackets or strings). These exceptions contain a `code` property prefixed with `CHARACTER_PARSER:` for specific error identification.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always chain `parse()` calls by passing the state: `let state = parse(firstPart); state = parse(secondPart, state);`.","message":"When using `parse()` to process a string in multiple sections, it is critical to pass the `state` object returned by the previous `parse()` call to the subsequent call. Failing to do so will reset the parser's internal state (e.g., stack of open brackets, in-string status), leading to incorrect parsing results.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Change the import path to reference only the main package: `import { someExport } from 'character-parser'`.","cause":"Attempting to import a module from an internal path (e.g., `character-parser/lib/util`) instead of the main package export.","error":"ERR_PACKAGE_PATH_NOT_EXPORTED"},{"fix":"Use ES module named imports: `import { parse, parseUntil } from 'character-parser'`. Ensure your environment supports ES Modules or transpile accordingly.","cause":"Trying to use CommonJS `require()` for named exports in a context where `character-parser@4.0.0` is resolved as an ES Module, or attempting a default import for a named export.","error":"TypeError: parse is not a function"},{"fix":"Review the input string for syntax errors, specifically ensuring all string delimiters (single quotes, double quotes, backticks) are properly matched and escaped where necessary.","cause":"The input JavaScript snippet contains an unclosed string literal.","error":"CHARACTER_PARSER:UNTERMINATED_STRING"}],"ecosystem":"npm"}