{"version":3,"file":"jpz-BlYPCRBg.mjs","names":[],"sources":["../src/jpz.ts"],"sourcesContent":["/**\n * Parser for JPZ crossword format (Crossword Compiler)\n * JPZ is an XML-based format\n */\n\nimport { XMLParser } from \"fast-xml-parser\";\nimport { UnsupportedPuzzleTypeError, JpzParseError } from \"./errors\";\nimport type {\n  Puzzle,\n  Grid,\n  Cell as UnifiedCell,\n  Clues,\n  ParseOptions,\n} from \"./types\";\nimport { ErrorCode } from \"./types\";\nimport { MAX_GRID_WIDTH, MAX_GRID_HEIGHT } from \"./constants\";\n\n// Type definitions for XML parser output\ninterface JpzXmlNode {\n  [key: string]: unknown;\n  \"@_width\"?: string;\n  \"@_height\"?: string;\n  \"@_x\"?: string;\n  \"@_y\"?: string;\n  \"@_type\"?: string;\n  \"@_solution\"?: string;\n  \"@_letter\"?: string;\n  \"@_number\"?: string;\n  \"@_background-shape\"?: string;\n  \"@_background-color\"?: string;\n  \"@_top-bar\"?: string;\n  \"@_bottom-bar\"?: string;\n  \"@_left-bar\"?: string;\n  \"@_right-bar\"?: string;\n  \"@_title\"?: string;\n  \"@_format\"?: string;\n  \"@_text\"?: string;\n  \"@_word\"?: string;\n  \"@_id\"?: string;\n  \"#text\"?: string;\n  cell?: JpzXmlNode | JpzXmlNode[];\n  cells?: { cell?: JpzXmlNode | JpzXmlNode[] };\n  title?: string | { b?: string; \"#text\"?: string };\n  creator?: string;\n  author?: string;\n  copyright?: string;\n  description?: string;\n  publisher?: string;\n  identifier?: string;\n  clue?: JpzXmlNode | JpzXmlNode[];\n  text?: string;\n  number?: string;\n  word?: JpzXmlNode | JpzXmlNode[];\n  // Additional properties found in parsing\n  \"rectangular-puzzle\"?: JpzXmlNode;\n  puzzle?: JpzXmlNode;\n  crossword?: JpzXmlNode;\n  coded?: unknown;\n  sudoku?: unknown;\n  kakuro?: unknown;\n  \"word-search\"?: unknown;\n  wordsearch?: unknown;\n  metadata?: JpzXmlNode;\n  grid?: JpzXmlNode;\n  Grid?: JpzXmlNode;\n  clues?: JpzXmlNode | JpzXmlNode[];\n  Clues?: JpzXmlNode | JpzXmlNode[];\n  words?: JpzXmlNode;\n  Words?: JpzXmlNode;\n}\n\ninterface JpzXmlRoot {\n  \"crossword-compiler-applet\"?: JpzXmlNode;\n  \"crossword-compiler\"?: JpzXmlNode;\n  puzzle?: JpzXmlNode;\n  crossword?: JpzXmlNode;\n}\n\n// Type guards\nfunction isJpzXmlNode(value: unknown): value is JpzXmlNode {\n  return typeof value === \"object\" && value !== null;\n}\n\nfunction isString(value: unknown): value is string {\n  return typeof value === \"string\";\n}\n\nfunction parseStringAttribute(value: unknown): string | undefined {\n  return isString(value) ? value : undefined;\n}\n\nfunction parseIntAttribute(value: unknown): number | undefined {\n  if (isString(value)) {\n    const parsed = Number.parseInt(value, 10);\n    return Number.isNaN(parsed) ? undefined : parsed;\n  }\n  return undefined;\n}\n\nexport interface JpzMetadata {\n  title?: string;\n  creator?: string;\n  copyright?: string;\n  description?: string;\n  publisher?: string;\n  identifier?: string;\n}\n\nexport interface JpzCell {\n  x: number;\n  y: number;\n  solution?: string;\n  number?: number;\n  type?: \"block\" | \"cell\";\n  isCircled?: boolean;\n  backgroundColor?: string;\n  barTop?: boolean;\n  barBottom?: boolean;\n  barLeft?: boolean;\n  barRight?: boolean;\n}\n\nexport interface JpzClue {\n  number: string | number;\n  text: string;\n  format?: string;\n}\n\nexport interface JpzWord {\n  id: string;\n  cells: Array<{ x: number; y: number }>;\n}\n\nexport interface JpzPuzzle {\n  width: number;\n  height: number;\n  metadata: JpzMetadata;\n  grid: JpzCell[][];\n  across: JpzClue[];\n  down: JpzClue[];\n  words?: JpzWord[];\n}\n\nfunction parseMetadata(metadataNode: unknown): JpzMetadata {\n  if (!isJpzXmlNode(metadataNode)) return {};\n\n  return {\n    title: parseStringAttribute(metadataNode.title),\n    creator:\n      parseStringAttribute(metadataNode.creator) ||\n      parseStringAttribute(metadataNode.author),\n    copyright: parseStringAttribute(metadataNode.copyright),\n    description: parseStringAttribute(metadataNode.description),\n    publisher: parseStringAttribute(metadataNode.publisher),\n    identifier: parseStringAttribute(metadataNode.identifier),\n  };\n}\n\nfunction parseCells(\n  gridNode: unknown,\n  options?: ParseOptions,\n): {\n  cells: Map<string, JpzCell>;\n  width: number;\n  height: number;\n} {\n  const cells = new Map<string, JpzCell>();\n\n  if (!isJpzXmlNode(gridNode)) {\n    throw new JpzParseError(\n      \"Missing or invalid grid element\",\n      ErrorCode.JPZ_MISSING_GRID,\n    );\n  }\n\n  const width = parseIntAttribute(gridNode[\"@_width\"]);\n  const height = parseIntAttribute(gridNode[\"@_height\"]);\n\n  if (width === undefined || height === undefined) {\n    throw new JpzParseError(\n      \"Grid dimensions (width and height) are required\",\n      ErrorCode.JPZ_INVALID_GRID,\n    );\n  }\n\n  // Validate grid dimensions to prevent excessive memory usage\n  const maxWidth = options?.maxGridSize?.width ?? MAX_GRID_WIDTH;\n  const maxHeight = options?.maxGridSize?.height ?? MAX_GRID_HEIGHT;\n\n  if (width <= 0 || width > maxWidth || height <= 0 || height > maxHeight) {\n    throw new JpzParseError(\n      `Invalid grid dimensions: ${width}x${height}. Maximum supported size is ${maxWidth}x${maxHeight}`,\n      ErrorCode.JPZ_INVALID_GRID,\n      { details: { width, height } },\n    );\n  }\n\n  // Handle cells - can be a single cell or array\n  const cellNodes = gridNode.cell;\n  if (cellNodes) {\n    const cellArray = Array.isArray(cellNodes) ? cellNodes : [cellNodes];\n\n    for (const cellNode of cellArray) {\n      if (!isJpzXmlNode(cellNode)) continue;\n\n      const x = parseIntAttribute(cellNode[\"@_x\"]);\n      const y = parseIntAttribute(cellNode[\"@_y\"]);\n\n      if (x === undefined || y === undefined) continue;\n\n      const key = `${x},${y}`;\n\n      const jpzCell: JpzCell = {\n        x,\n        y,\n        type:\n          parseStringAttribute(cellNode[\"@_type\"]) === \"block\"\n            ? \"block\"\n            : \"cell\",\n        solution:\n          parseStringAttribute(cellNode[\"@_solution\"]) ||\n          parseStringAttribute(cellNode[\"@_letter\"]),\n        number: parseIntAttribute(cellNode[\"@_number\"]),\n        isCircled:\n          parseStringAttribute(cellNode[\"@_background-shape\"]) === \"circle\",\n        backgroundColor: parseStringAttribute(cellNode[\"@_background-color\"]),\n        barTop: parseStringAttribute(cellNode[\"@_top-bar\"]) === \"true\",\n        barBottom: parseStringAttribute(cellNode[\"@_bottom-bar\"]) === \"true\",\n        barLeft: parseStringAttribute(cellNode[\"@_left-bar\"]) === \"true\",\n        barRight: parseStringAttribute(cellNode[\"@_right-bar\"]) === \"true\",\n      };\n\n      cells.set(key, jpzCell);\n    }\n  }\n\n  return { cells, width, height };\n}\n\nfunction buildGrid(\n  cells: Map<string, JpzCell>,\n  width: number,\n  height: number,\n): JpzCell[][] {\n  const grid: JpzCell[][] = [];\n\n  // JPZ uses 1-based indexing\n  for (let y = 1; y <= height; y++) {\n    const row: JpzCell[] = [];\n    for (let x = 1; x <= width; x++) {\n      const key = `${x},${y}`;\n      const cell = cells.get(key);\n\n      if (cell) {\n        row.push(cell);\n      } else {\n        // Default empty cell\n        row.push({\n          x,\n          y,\n          type: \"cell\",\n        });\n      }\n    }\n    grid.push(row);\n  }\n\n  return grid;\n}\n\nfunction parseClues(cluesNode: unknown): {\n  across: JpzClue[];\n  down: JpzClue[];\n} {\n  const across: JpzClue[] = [];\n  const down: JpzClue[] = [];\n\n  if (!isJpzXmlNode(cluesNode)) {\n    return { across, down };\n  }\n\n  // Handle different clue structures\n  const clueArrays = Array.isArray(cluesNode) ? cluesNode : [cluesNode];\n\n  for (const clueSet of clueArrays) {\n    if (!isJpzXmlNode(clueSet)) continue;\n\n    // Get title/direction - might be nested object with text content\n    let titleStr = \"\";\n    if (isString(clueSet.title)) {\n      titleStr = clueSet.title;\n    } else if (isJpzXmlNode(clueSet.title)) {\n      // Handle nested elements like <title><b>Across</b></title>\n      const titleNode = clueSet.title;\n      titleStr =\n        parseStringAttribute(titleNode.b) ||\n        parseStringAttribute(titleNode[\"#text\"]) ||\n        JSON.stringify(titleNode);\n    } else if (parseStringAttribute(clueSet[\"@_title\"])) {\n      titleStr = parseStringAttribute(clueSet[\"@_title\"]) || \"\";\n    }\n\n    const isAcross = titleStr.toLowerCase().includes(\"across\");\n    const targetArray = isAcross ? across : down;\n\n    // Get clues\n    const clueNodes = clueSet.clue;\n    if (clueNodes) {\n      const clues = Array.isArray(clueNodes) ? clueNodes : [clueNodes];\n\n      for (const clue of clues) {\n        if (isString(clue)) {\n          // Simple string clue with number prefix\n          const match = clue.match(/^(\\d+)\\.\\s*(.+)$/);\n          if (match) {\n            targetArray.push({\n              number: match[1] || \"\",\n              text: match[2] || \"\",\n            });\n          }\n        } else if (isJpzXmlNode(clue)) {\n          // Structured clue\n          const clueObj: JpzClue = {\n            number:\n              parseStringAttribute(clue[\"@_number\"]) ||\n              parseStringAttribute(clue.number) ||\n              \"\",\n            text:\n              parseStringAttribute(clue[\"#text\"]) ||\n              parseStringAttribute(clue.text) ||\n              parseStringAttribute(clue[\"@_text\"]) ||\n              \"\",\n            format: parseStringAttribute(clue[\"@_format\"]),\n          };\n\n          // Handle word reference\n          const wordRef = parseStringAttribute(clue[\"@_word\"]);\n          if (wordRef) {\n            clueObj.number = wordRef;\n          }\n\n          targetArray.push(clueObj);\n        }\n      }\n    }\n  }\n\n  return { across, down };\n}\n\nfunction parseWords(wordsNode: unknown): JpzWord[] {\n  const words: JpzWord[] = [];\n\n  if (!isJpzXmlNode(wordsNode) || !wordsNode.word) {\n    return words;\n  }\n\n  const wordNodes = Array.isArray(wordsNode.word)\n    ? wordsNode.word\n    : [wordsNode.word];\n\n  for (const word of wordNodes) {\n    if (!isJpzXmlNode(word)) continue;\n\n    const jpzWord: JpzWord = {\n      id: parseStringAttribute(word[\"@_id\"]) || \"\",\n      cells: [],\n    };\n\n    // Parse cells\n    if (isJpzXmlNode(word.cells)) {\n      const cellList = word.cells.cell;\n      if (cellList) {\n        const cells = Array.isArray(cellList) ? cellList : [cellList];\n        for (const cell of cells) {\n          if (!isJpzXmlNode(cell)) continue;\n\n          const x = parseIntAttribute(cell[\"@_x\"]);\n          const y = parseIntAttribute(cell[\"@_y\"]);\n\n          if (x !== undefined && y !== undefined) {\n            jpzWord.cells.push({ x, y });\n          }\n        }\n      }\n    }\n\n    words.push(jpzWord);\n  }\n\n  return words;\n}\n\n/**\n * Parse a JPZ format crossword puzzle.\n *\n * @param content - The JPZ XML data as string\n * @param options - Optional parsing options\n * @param options.maxGridSize - Maximum allowed grid dimensions\n * @returns A JpzPuzzle object containing all puzzle data\n * @throws {JpzParseError} When the content is not valid JPZ format\n * @throws {UnsupportedPuzzleTypeError} When the puzzle is not a crossword\n *\n * @example\n * ```typescript\n * import { parseJpz } from 'xword-parser';\n * const jpzData = '<?xml version=\"1.0\"?><crossword-compiler-applet>...';\n * const puzzle = parseJpz(jpzData);\n * ```\n */\nexport function parseJpz(content: string, options?: ParseOptions): JpzPuzzle {\n  const parser = new XMLParser({\n    ignoreAttributes: false,\n    attributeNamePrefix: \"@_\",\n    textNodeName: \"#text\",\n    parseAttributeValue: false,\n  });\n\n  let doc: JpzXmlRoot;\n  try {\n    doc = parser.parse(content) as JpzXmlRoot;\n  } catch (e) {\n    throw new JpzParseError(\n      `Invalid XML: ${e instanceof Error ? e.message : \"Unknown error\"}`,\n      ErrorCode.JPZ_INVALID_XML,\n      undefined,\n      e,\n    );\n  }\n\n  // Handle different JPZ root elements\n  const puzzleRoot =\n    doc[\"crossword-compiler-applet\"] ||\n    doc[\"crossword-compiler\"] ||\n    doc.puzzle ||\n    doc.crossword;\n\n  if (!isJpzXmlNode(puzzleRoot)) {\n    throw new JpzParseError(\n      \"no recognized root element\",\n      ErrorCode.JPZ_INVALID_XML,\n    );\n  }\n\n  // Find the puzzle data - might be nested\n  let rectangularPuzzle = puzzleRoot[\"rectangular-puzzle\"];\n  if (!isJpzXmlNode(rectangularPuzzle) && isJpzXmlNode(puzzleRoot.puzzle)) {\n    const puzzleChild = puzzleRoot.puzzle;\n    if (isJpzXmlNode(puzzleChild)) {\n      rectangularPuzzle = puzzleChild[\"rectangular-puzzle\"];\n    }\n  }\n  if (!isJpzXmlNode(rectangularPuzzle)) {\n    rectangularPuzzle = puzzleRoot;\n  }\n\n  // Check if this is a non-crossword puzzle type we don't support\n  if (rectangularPuzzle.coded) {\n    throw new UnsupportedPuzzleTypeError(\"Coded/cipher crosswords (Kaidoku)\");\n  }\n  if (rectangularPuzzle.sudoku || rectangularPuzzle.kakuro) {\n    throw new UnsupportedPuzzleTypeError(\"Number puzzles\");\n  }\n  if (rectangularPuzzle[\"word-search\"] || rectangularPuzzle.wordsearch) {\n    throw new UnsupportedPuzzleTypeError(\"Word search\");\n  }\n\n  // Extract components\n  const metadata = parseMetadata(rectangularPuzzle.metadata);\n\n  // Find grid and clues - should be in crossword section for standard crosswords\n  const crosswordNode =\n    rectangularPuzzle.crossword ||\n    rectangularPuzzle.puzzle ||\n    rectangularPuzzle;\n\n  let gridNode: unknown = undefined;\n  if (isJpzXmlNode(crosswordNode)) {\n    gridNode = crosswordNode.grid || crosswordNode.Grid;\n  }\n  if (!gridNode && isJpzXmlNode(rectangularPuzzle)) {\n    gridNode = rectangularPuzzle.grid;\n  }\n\n  if (!gridNode) {\n    throw new JpzParseError(\"no grid found\", ErrorCode.JPZ_INVALID_XML);\n  }\n\n  // Parse cells and build grid\n  const { cells, width, height } = parseCells(gridNode, options);\n  const grid = buildGrid(cells, width, height);\n\n  // Parse clues - might be in different locations\n  let cluesNode: unknown = undefined;\n  if (isJpzXmlNode(crosswordNode)) {\n    cluesNode = crosswordNode.clues || crosswordNode.Clues;\n  }\n  if (!cluesNode && isJpzXmlNode(rectangularPuzzle)) {\n    cluesNode = rectangularPuzzle.clues || rectangularPuzzle.Clues;\n  }\n\n  const { across, down } = parseClues(cluesNode);\n\n  // Parse words if present\n  let wordsNode: unknown = undefined;\n  if (isJpzXmlNode(crosswordNode)) {\n    wordsNode = crosswordNode.words || crosswordNode.Words;\n  }\n  const words = wordsNode ? parseWords(wordsNode) : undefined;\n\n  return {\n    width,\n    height,\n    metadata,\n    grid,\n    across,\n    down,\n    words,\n  };\n}\n\n/**\n * Convert a JPZ puzzle to the unified Puzzle format.\n *\n * @param puzzle - The JpzPuzzle object to convert\n * @returns A unified Puzzle object\n *\n * @example\n * ```typescript\n * import { parseJpz, convertJpzToUnified } from 'xword-parser';\n * const jpzPuzzle = parseJpz(jpzData);\n * const unifiedPuzzle = convertJpzToUnified(jpzPuzzle);\n * ```\n */\nexport function convertJpzToUnified(puzzle: JpzPuzzle): Puzzle {\n  const grid: Grid = {\n    width: puzzle.width,\n    height: puzzle.height,\n    cells: [],\n  };\n\n  // Convert grid\n  for (const row of puzzle.grid) {\n    const cellRow: UnifiedCell[] = [];\n    for (const cell of row) {\n      const unifiedCell: UnifiedCell = {\n        solution: cell.solution,\n        number: cell.number,\n        isBlack: cell.type === \"block\",\n        isCircled: cell.isCircled,\n      };\n\n      // Add cell-specific metadata if present\n      if (\n        cell.backgroundColor ||\n        cell.barTop ||\n        cell.barBottom ||\n        cell.barLeft ||\n        cell.barRight\n      ) {\n        unifiedCell.additionalProperties = {};\n        if (cell.backgroundColor) {\n          unifiedCell.additionalProperties.backgroundColor =\n            cell.backgroundColor;\n        }\n        if (cell.barTop) unifiedCell.additionalProperties.barTop = cell.barTop;\n        if (cell.barBottom)\n          unifiedCell.additionalProperties.barBottom = cell.barBottom;\n        if (cell.barLeft)\n          unifiedCell.additionalProperties.barLeft = cell.barLeft;\n        if (cell.barRight)\n          unifiedCell.additionalProperties.barRight = cell.barRight;\n      }\n\n      cellRow.push(unifiedCell);\n    }\n    grid.cells.push(cellRow);\n  }\n\n  // Convert clues\n  const clues: Clues = {\n    across: puzzle.across.map((c) => ({\n      number: typeof c.number === \"string\" ? parseInt(c.number) : c.number,\n      text: c.text,\n    })),\n    down: puzzle.down.map((c) => ({\n      number: typeof c.number === \"string\" ? parseInt(c.number) : c.number,\n      text: c.text,\n    })),\n  };\n\n  const result: Puzzle = {\n    title: puzzle.metadata.title,\n    author: puzzle.metadata.creator,\n    copyright: puzzle.metadata.copyright,\n    grid,\n    clues,\n  };\n\n  // Add puzzle-level metadata if present\n  const additionalProps: Record<string, unknown> = {};\n\n  if (puzzle.metadata.description)\n    additionalProps.description = puzzle.metadata.description;\n  if (puzzle.metadata.publisher)\n    additionalProps.publisher = puzzle.metadata.publisher;\n  if (puzzle.metadata.identifier)\n    additionalProps.identifier = puzzle.metadata.identifier;\n\n  // Add words information if present\n  if (puzzle.words && puzzle.words.length > 0) {\n    additionalProps.words = puzzle.words;\n  }\n\n  if (Object.keys(additionalProps).length > 0) {\n    result.additionalProperties = additionalProps;\n  }\n\n  return result;\n}\n"],"mappings":"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"}